[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Final changes for linux 2.6.13 rebasing and some directory reorgs
# HG changeset patch # User djm@xxxxxxxxxxxxxxx # Node ID 3ca4ca7a9cc234d33c3981852fc37c73fcd72218 # Parent d34925e4144bcdadb020ee2deef766a994bf7b04 Final changes for linux 2.6.13 rebasing and some directory reorgs diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/Makefile Thu Sep 1 18:46:28 2005 @@ -1,9 +1,6 @@ include $(BASEDIR)/Rules.mk -VPATH = linux linux-xen linux/lib -#VPATH = linux-xen linux/lib - -# libs-y += arch/ia64/lib/lib.a +VPATH = xen vmx linux linux-xen OBJS = xensetup.o setup.o time.o irq.o ia64_ksyms.o process.o smp.o \ xenmisc.o acpi.o hypercall.o \ @@ -15,8 +12,6 @@ irq_ia64.o irq_lsapic.o vhpt.o xenasm.o hyperprivop.o dom_fw.o \ grant_table.o sn_console.o -#OBJS += idiv64.o idiv32.o \ - # TMP holder to contain *.0 moved out of CONFIG_VTI OBJS += vmx_init.o @@ -27,7 +22,7 @@ pal_emul.o vmx_irq_ia64.o endif -# files from xen/arch/ia64/linux/lib (linux/arch/ia64/lib) +# lib files from xen/arch/ia64/linux/ (linux/arch/ia64/lib) OBJS += bitop.o clear_page.o flush.o copy_page_mck.o \ memset.o strlen.o memcpy_mck.o \ __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ @@ -86,9 +81,9 @@ touch $@ # I'm sure a Makefile wizard would know a better way to do this -xen.lds.s: xen.lds.S +xen.lds.s: xen/xen.lds.S $(CC) -E $(CPPFLAGS) -P -DXEN -D__ASSEMBLY__ \ - -o xen.lds.s xen.lds.S + -o xen.lds.s xen/xen.lds.S # variants of divide/modulo # see files in xen/arch/ia64/linux/lib (linux/arch/ia64/lib) @@ -111,7 +106,7 @@ clean: - rm -f *.o *~ core xen.lds.s $(BASEDIR)/include/asm-ia64/.offsets.h.stamp asm-offsets.s + rm -f *.o *~ core xen.lds.s $(BASEDIR)/include/asm-ia64/.offsets.h.stamp asm-offsets.s map.out rm -f asm-xsi-offsets.s $(BASEDIR)/include/asm-ia64/asm-xsi-offsets.h rm -f linux/lib/*.o diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/README.origin --- a/xen/arch/ia64/linux/README.origin Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/README.origin Thu Sep 1 18:46:28 2005 @@ -13,12 +13,13 @@ machvec.c -> linux/arch/ia64/kernel/machvec.c patch.c -> linux/arch/ia64/kernel/patch.c pcdp.h -> drivers/firmware/pcdp.h -lib/bitop.c -> linux/arch/ia64/lib/bitop.c -lib/clear_page.S -> linux/arch/ia64/lib/clear_page.S -lib/copy_page_mck.S -> linux/arch/ia64/lib/copy_page_mck.S -lib/flush.S -> linux/arch/ia64/lib/flush.S -lib/idiv32.S -> linux/arch/ia64/lib/idiv32.S -lib/idiv64.S -> linux/arch/ia64/lib/idiv64.S -lib/memcpy_mck.S -> linux/arch/ia64/lib/memcpy_mck.S -lib/memset.S -> linux/arch/ia64/lib/memset.S -lib/strlen.S -> linux/arch/ia64/lib/strlen.S + +bitop.c -> linux/arch/ia64/lib/bitop.c +clear_page.S -> linux/arch/ia64/lib/clear_page.S +copy_page_mck.S -> linux/arch/ia64/lib/copy_page_mck.S +flush.S -> linux/arch/ia64/lib/flush.S +idiv32.S -> linux/arch/ia64/lib/idiv32.S +idiv64.S -> linux/arch/ia64/lib/idiv64.S +memcpy_mck.S -> linux/arch/ia64/lib/memcpy_mck.S +memset.S -> linux/arch/ia64/lib/memset.S +strlen.S -> linux/arch/ia64/lib/strlen.S diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/config.h --- a/xen/include/asm-ia64/config.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/config.h Thu Sep 1 18:46:28 2005 @@ -203,6 +203,7 @@ #endif // CONFIG_VTI #define __attribute_used__ __attribute__ ((unused)) +#define __nocast // see include/asm-x86/atomic.h (different from standard linux) #define _atomic_set(v,i) (((v).counter) = (i)) @@ -262,9 +263,6 @@ // these declarations got moved at some point, find a better place for them extern int ht_per_core; -// needed for include/xen/smp.h -#define __smp_processor_id() 0 - // xen/include/asm/config.h /****************************************************************************** * config.h @@ -297,6 +295,10 @@ #endif /* __ASSEMBLY__ */ #endif /* __XEN_IA64_CONFIG_H__ */ +// needed for include/xen/smp.h +#define __smp_processor_id() 0 + + // FOLLOWING ADDED FOR XEN POST-NGIO and/or LINUX 2.6.7 // following derived from linux/include/linux/compiler-gcc3.h diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/bug.h --- a/xen/include/asm-ia64/linux/asm-generic/bug.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/bug.h Thu Sep 1 18:46:28 2005 @@ -4,17 +4,11 @@ #include <linux/compiler.h> #include <linux/config.h> +#ifdef CONFIG_BUG #ifndef HAVE_ARCH_BUG #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ panic("BUG!"); \ -} while (0) -#endif - -#ifndef HAVE_ARCH_PAGE_BUG -#define PAGE_BUG(page) do { \ - printk("page BUG for page at %p\n", page); \ - BUG(); \ } while (0) #endif @@ -31,4 +25,18 @@ } while (0) #endif +#else /* !CONFIG_BUG */ +#ifndef HAVE_ARCH_BUG +#define BUG() #endif + +#ifndef HAVE_ARCH_BUG_ON +#define BUG_ON(condition) do { if (condition) ; } while(0) +#endif + +#ifndef HAVE_ARCH_WARN_ON +#define WARN_ON(condition) do { if (condition) ; } while(0) +#endif +#endif + +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/errno.h --- a/xen/include/asm-ia64/linux/asm-generic/errno.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/errno.h Thu Sep 1 18:46:28 2005 @@ -102,4 +102,8 @@ #define EKEYREVOKED 128 /* Key has been revoked */ #define EKEYREJECTED 129 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + #endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/iomap.h --- a/xen/include/asm-ia64/linux/asm-generic/iomap.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/iomap.h Thu Sep 1 18:46:28 2005 @@ -2,6 +2,7 @@ #define __GENERIC_IO_H #include <linux/linkage.h> +#include <asm/byteorder.h> /* * These are the "generic" interfaces for doing new-style @@ -26,11 +27,15 @@ */ extern unsigned int fastcall ioread8(void __iomem *); extern unsigned int fastcall ioread16(void __iomem *); +extern unsigned int fastcall ioread16be(void __iomem *); extern unsigned int fastcall ioread32(void __iomem *); +extern unsigned int fastcall ioread32be(void __iomem *); extern void fastcall iowrite8(u8, void __iomem *); extern void fastcall iowrite16(u16, void __iomem *); +extern void fastcall iowrite16be(u16, void __iomem *); extern void fastcall iowrite32(u32, void __iomem *); +extern void fastcall iowrite32be(u32, void __iomem *); /* * "string" versions of the above. Note that they diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/pci.h --- a/xen/include/asm-ia64/linux/asm-generic/pci.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/pci.h Thu Sep 1 18:46:28 2005 @@ -22,6 +22,14 @@ region->end = res->end; } +static inline void +pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) +{ + res->start = region->start; + res->end = region->end; +} + #define pcibios_scan_all_fns(a, b) 0 #ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/pgtable-nopud.h --- a/xen/include/asm-ia64/linux/asm-generic/pgtable-nopud.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/pgtable-nopud.h Thu Sep 1 18:46:28 2005 @@ -2,6 +2,8 @@ #define _PGTABLE_NOPUD_H #ifndef __ASSEMBLY__ + +#define __PAGETABLE_PUD_FOLDED /* * Having the pud type consist of a pgd gets the size right, and allows @@ -52,5 +54,8 @@ #define pud_free(x) do { } while (0) #define __pud_free_tlb(tlb, x) do { } while (0) +#undef pud_addr_end +#define pud_addr_end(addr, end) (end) + #endif /* __ASSEMBLY__ */ #endif /* _PGTABLE_NOPUD_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/pgtable.h --- a/xen/include/asm-ia64/linux/asm-generic/pgtable.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/pgtable.h Thu Sep 1 18:46:28 2005 @@ -16,7 +16,7 @@ #ifndef __HAVE_ARCH_SET_PTE_ATOMIC #define ptep_establish(__vma, __address, __ptep, __entry) \ do { \ - set_pte(__ptep, __entry); \ + set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ flush_tlb_page(__vma, __address); \ } while (0) #else /* __HAVE_ARCH_SET_PTE_ATOMIC */ @@ -37,26 +37,30 @@ */ #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ do { \ - set_pte(__ptep, __entry); \ + set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ flush_tlb_page(__vma, __address); \ } while (0) #endif #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(pte_t *ptep) -{ - pte_t pte = *ptep; - if (!pte_young(pte)) - return 0; - set_pte(ptep, pte_mkold(pte)); - return 1; -} +#define ptep_test_and_clear_young(__vma, __address, __ptep) \ +({ \ + pte_t __pte = *(__ptep); \ + int r = 1; \ + if (!pte_young(__pte)) \ + r = 0; \ + else \ + set_pte_at((__vma)->vm_mm, (__address), \ + (__ptep), pte_mkold(__pte)); \ + r; \ +}) #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH #define ptep_clear_flush_young(__vma, __address, __ptep) \ ({ \ - int __young = ptep_test_and_clear_young(__ptep); \ + int __young; \ + __young = ptep_test_and_clear_young(__vma, __address, __ptep); \ if (__young) \ flush_tlb_page(__vma, __address); \ __young; \ @@ -64,20 +68,24 @@ #endif #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY -static inline int ptep_test_and_clear_dirty(pte_t *ptep) -{ - pte_t pte = *ptep; - if (!pte_dirty(pte)) - return 0; - set_pte(ptep, pte_mkclean(pte)); - return 1; -} +#define ptep_test_and_clear_dirty(__vma, __address, __ptep) \ +({ \ + pte_t __pte = *__ptep; \ + int r = 1; \ + if (!pte_dirty(__pte)) \ + r = 0; \ + else \ + set_pte_at((__vma)->vm_mm, (__address), (__ptep), \ + pte_mkclean(__pte)); \ + r; \ +}) #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH #define ptep_clear_flush_dirty(__vma, __address, __ptep) \ ({ \ - int __dirty = ptep_test_and_clear_dirty(__ptep); \ + int __dirty; \ + __dirty = ptep_test_and_clear_dirty(__vma, __address, __ptep); \ if (__dirty) \ flush_tlb_page(__vma, __address); \ __dirty; \ @@ -85,36 +93,29 @@ #endif #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR -static inline pte_t ptep_get_and_clear(pte_t *ptep) -{ - pte_t pte = *ptep; - pte_clear(ptep); - return pte; -} +#define ptep_get_and_clear(__mm, __address, __ptep) \ +({ \ + pte_t __pte = *(__ptep); \ + pte_clear((__mm), (__address), (__ptep)); \ + __pte; \ +}) #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH #define ptep_clear_flush(__vma, __address, __ptep) \ ({ \ - pte_t __pte = ptep_get_and_clear(__ptep); \ + pte_t __pte; \ + __pte = ptep_get_and_clear((__vma)->vm_mm, __address, __ptep); \ flush_tlb_page(__vma, __address); \ __pte; \ }) #endif #ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT -static inline void ptep_set_wrprotect(pte_t *ptep) +static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) { pte_t old_pte = *ptep; - set_pte(ptep, pte_wrprotect(old_pte)); -} -#endif - -#ifndef __HAVE_ARCH_PTEP_MKDIRTY -static inline void ptep_mkdirty(pte_t *ptep) -{ - pte_t old_pte = *ptep; - set_pte(ptep, pte_mkdirty(old_pte)); + set_pte_at(mm, address, ptep, pte_wrprotect(old_pte)); } #endif @@ -124,6 +125,9 @@ #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY #define page_test_and_clear_dirty(page) (0) +#define pte_maybe_dirty(pte) pte_dirty(pte) +#else +#define pte_maybe_dirty(pte) (1) #endif #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG @@ -134,4 +138,77 @@ #define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) #endif +#ifndef __HAVE_ARCH_LAZY_MMU_PROT_UPDATE +#define lazy_mmu_prot_update(pte) do { } while (0) +#endif + +/* + * When walking page tables, get the address of the next boundary, + * or the end address of the range if that comes earlier. Although no + * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout. + */ + +#define pgd_addr_end(addr, end) \ +({ unsigned long __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \ + (__boundary - 1 < (end) - 1)? __boundary: (end); \ +}) + +#ifndef pud_addr_end +#define pud_addr_end(addr, end) \ +({ unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK; \ + (__boundary - 1 < (end) - 1)? __boundary: (end); \ +}) +#endif + +#ifndef pmd_addr_end +#define pmd_addr_end(addr, end) \ +({ unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \ + (__boundary - 1 < (end) - 1)? __boundary: (end); \ +}) +#endif + +#ifndef __ASSEMBLY__ +/* + * When walking page tables, we usually want to skip any p?d_none entries; + * and any p?d_bad entries - reporting the error before resetting to none. + * Do the tests inline, but report and clear the bad entry in mm/memory.c. + */ +void pgd_clear_bad(pgd_t *); +void pud_clear_bad(pud_t *); +void pmd_clear_bad(pmd_t *); + +static inline int pgd_none_or_clear_bad(pgd_t *pgd) +{ + if (pgd_none(*pgd)) + return 1; + if (unlikely(pgd_bad(*pgd))) { + pgd_clear_bad(pgd); + return 1; + } + return 0; +} + +static inline int pud_none_or_clear_bad(pud_t *pud) +{ + if (pud_none(*pud)) + return 1; + if (unlikely(pud_bad(*pud))) { + pud_clear_bad(pud); + return 1; + } + return 0; +} + +static inline int pmd_none_or_clear_bad(pmd_t *pmd) +{ + if (pmd_none(*pmd)) + return 1; + if (unlikely(pmd_bad(*pmd))) { + pmd_clear_bad(pmd); + return 1; + } + return 0; +} +#endif /* !__ASSEMBLY__ */ + #endif /* _ASM_GENERIC_PGTABLE_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/sections.h --- a/xen/include/asm-ia64/linux/asm-generic/sections.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/sections.h Thu Sep 1 18:46:28 2005 @@ -8,6 +8,9 @@ extern char __bss_start[], __bss_stop[]; extern char __init_begin[], __init_end[]; extern char _sinittext[], _einittext[]; +extern char _sextratext[] __attribute__((weak)); +extern char _eextratext[] __attribute__((weak)); extern char _end[]; +extern char __per_cpu_start[], __per_cpu_end[]; #endif /* _ASM_GENERIC_SECTIONS_H_ */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/topology.h --- a/xen/include/asm-ia64/linux/asm-generic/topology.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/topology.h Thu Sep 1 18:46:28 2005 @@ -41,8 +41,15 @@ #ifndef node_to_first_cpu #define node_to_first_cpu(node) (0) #endif +#ifndef pcibus_to_node +#define pcibus_to_node(node) (-1) +#endif + #ifndef pcibus_to_cpumask -#define pcibus_to_cpumask(bus) (cpu_online_map) +#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \ + CPU_MASK_ALL : \ + node_to_cpumask(pcibus_to_node(bus)) \ + ) #endif #endif /* _ASM_GENERIC_TOPOLOGY_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/vmlinux.lds.h --- a/xen/include/asm-ia64/linux/asm-generic/vmlinux.lds.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/vmlinux.lds.h Thu Sep 1 18:46:28 2005 @@ -73,7 +73,7 @@ } #define SECURITY_INIT \ - .security_initcall.init : { \ + .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__security_initcall_start) = .; \ *(.security_initcall.init) \ VMLINUX_SYMBOL(__security_initcall_end) = .; \ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/acpi.h --- a/xen/include/asm-ia64/linux/asm/acpi.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/acpi.h Thu Sep 1 18:46:28 2005 @@ -98,6 +98,15 @@ int acpi_request_vector (u32 int_type); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); +/* + * Record the cpei override flag and current logical cpu. This is + * useful for CPU removal. + */ +extern unsigned int can_cpei_retarget(void); +extern unsigned int is_cpu_cpei_target(unsigned int cpu); +extern void set_cpei_target_cpu(unsigned int cpu); +extern unsigned int get_cpei_target_cpu(void); + #ifdef CONFIG_ACPI_NUMA /* Proximity bitmap length; _PXM is at most 255 (8 bit)*/ #define MAX_PXM_DOMAINS (256) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/bitops.h --- a/xen/include/asm-ia64/linux/asm/bitops.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/bitops.h Thu Sep 1 18:46:28 2005 @@ -314,8 +314,8 @@ #ifdef __KERNEL__ /* - * find_last_zero_bit - find the last zero bit in a 64 bit quantity - * @x: The value to search + * Return bit number of last (most-significant) bit set. Undefined + * for x==0. Bits are numbered from 0..63 (e.g., ia64_fls(9) == 3). */ static inline unsigned long ia64_fls (unsigned long x) @@ -327,10 +327,23 @@ return exp - 0xffff; } +/* + * Find the last (most significant) bit set. Returns 0 for x==0 and + * bits are numbered from 1..32 (e.g., fls(9) == 4). + */ static inline int -fls (int x) -{ - return ia64_fls((unsigned int) x); +fls (int t) +{ + unsigned long x = t & 0xffffffffu; + + if (!x) + return 0; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ia64_popcnt(x); } /* @@ -353,9 +366,9 @@ return result; } -#define hweight32(x) hweight64 ((x) & 0xfffffffful) -#define hweight16(x) hweight64 ((x) & 0xfffful) -#define hweight8(x) hweight64 ((x) & 0xfful) +#define hweight32(x) (unsigned int) hweight64((x) & 0xfffffffful) +#define hweight16(x) (unsigned int) hweight64((x) & 0xfffful) +#define hweight8(x) (unsigned int) hweight64((x) & 0xfful) #endif /* __KERNEL__ */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/break.h --- a/xen/include/asm-ia64/linux/asm/break.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/break.h Thu Sep 1 18:46:28 2005 @@ -12,6 +12,8 @@ * OS-specific debug break numbers: */ #define __IA64_BREAK_KDB 0x80100 +#define __IA64_BREAK_KPROBE 0x80200 +#define __IA64_BREAK_JPROBE 0x80300 /* * OS-specific break numbers: diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/bug.h --- a/xen/include/asm-ia64/linux/asm/bug.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/bug.h Thu Sep 1 18:46:28 2005 @@ -1,6 +1,7 @@ #ifndef _ASM_IA64_BUG_H #define _ASM_IA64_BUG_H +#ifdef CONFIG_BUG #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) # define ia64_abort() __builtin_trap() #else @@ -8,8 +9,10 @@ #endif #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) -/* should this BUG should be made generic? */ +/* should this BUG be made generic? */ #define HAVE_ARCH_BUG +#endif + #include <asm-generic/bug.h> #endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/cacheflush.h --- a/xen/include/asm-ia64/linux/asm/cacheflush.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/cacheflush.h Thu Sep 1 18:46:28 2005 @@ -19,7 +19,7 @@ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) #define flush_cache_range(vma, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) #define flush_icache_page(vma,page) do { } while (0) #define flush_cache_vmap(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/param.h --- a/xen/include/asm-ia64/linux/asm/param.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/param.h Thu Sep 1 18:46:28 2005 @@ -27,7 +27,7 @@ */ # define HZ 32 # else -# define HZ 1024 +# define HZ CONFIG_HZ # endif # define USER_HZ HZ # define CLOCKS_PER_SEC HZ /* frequency at which times() counts */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/pci.h --- a/xen/include/asm-ia64/linux/asm/pci.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/pci.h Thu Sep 1 18:46:28 2005 @@ -47,7 +47,7 @@ } static inline void -pcibios_penalize_isa_irq (int irq) +pcibios_penalize_isa_irq (int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ } @@ -82,6 +82,25 @@ #define sg_dma_len(sg) ((sg)->dma_length) #define sg_dma_address(sg) ((sg)->dma_address) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_MULTIPLE; + *strategy_parameter = cacheline_size; +} +#endif + #define HAVE_PCI_MMAP extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); @@ -109,6 +128,7 @@ void *acpi_handle; void *iommu; int segment; + int node; /* nearest node with memory or -1 for global allocation */ unsigned int windows; struct pci_window *window; @@ -121,14 +141,9 @@ extern struct pci_ops pci_root_ops; -static inline int pci_name_bus(char *name, struct pci_bus *bus) +static inline int pci_proc_domain(struct pci_bus *bus) { - if (pci_domain_nr(bus) == 0) { - sprintf(name, "%02x", bus->number); - } else { - sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); - } - return 0; + return (pci_domain_nr(bus) != 0); } static inline void pcibios_add_platform_entries(struct pci_dev *dev) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/percpu.h --- a/xen/include/asm-ia64/linux/asm/percpu.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/percpu.h Thu Sep 1 18:46:28 2005 @@ -50,7 +50,7 @@ #else /* ! SMP */ -#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) +#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var #define per_cpu_init() (__phys_per_cpu_start) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/sections.h --- a/xen/include/asm-ia64/linux/asm/sections.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/sections.h Thu Sep 1 18:46:28 2005 @@ -17,6 +17,7 @@ extern char __start_gate_fsyscall_patchlist[], __end_gate_fsyscall_patchlist[]; extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_bubble_down_patchlist[]; extern char __start_unwind[], __end_unwind[]; +extern char __start_ivt_text[], __end_ivt_text[]; #endif /* _ASM_IA64_SECTIONS_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/signal.h --- a/xen/include/asm-ia64/linux/asm/signal.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/signal.h Thu Sep 1 18:46:28 2005 @@ -114,27 +114,11 @@ #define _NSIG_BPW 64 #define _NSIG_WORDS (_NSIG / _NSIG_BPW) -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 #define SA_PERCPU_IRQ 0x02000000 #endif /* __KERNEL__ */ -#define SIG_BLOCK 0 /* for blocking signals */ -#define SIG_UNBLOCK 1 /* for unblocking signals */ -#define SIG_SETMASK 2 /* for setting the signal mask */ - -#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ -#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ -#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ +#include <asm-generic/signal.h> # ifndef __ASSEMBLY__ @@ -142,9 +126,6 @@ /* Avoid too many header ordering problems. */ struct siginfo; - -/* Type of a signal handler. */ -typedef void __user (*__sighandler_t)(int); typedef struct sigaltstack { void __user *ss_sp; diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/smp.h --- a/xen/include/asm-ia64/linux/asm/smp.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/smp.h Thu Sep 1 18:46:28 2005 @@ -3,16 +3,14 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@xxxxxxxxxxx> - * Copyright (C) 2001-2003 Hewlett-Packard Co + * (c) Copyright 2001-2003, 2005 Hewlett-Packard Development Company, L.P. * David Mosberger-Tang <davidm@xxxxxxxxxx> + * Bjorn Helgaas <bjorn.helgaas@xxxxxx> */ #ifndef _ASM_IA64_SMP_H #define _ASM_IA64_SMP_H #include <linux/config.h> - -#ifdef CONFIG_SMP - #include <linux/init.h> #include <linux/threads.h> #include <linux/kernel.h> @@ -24,12 +22,31 @@ #include <asm/processor.h> #include <asm/ptrace.h> +static inline unsigned int +ia64_get_lid (void) +{ + union { + struct { + unsigned long reserved : 16; + unsigned long eid : 8; + unsigned long id : 8; + unsigned long ignored : 32; + } f; + unsigned long bits; + } lid; + + lid.bits = ia64_getreg(_IA64_REG_CR_LID); + return lid.f.id << 8 | lid.f.eid; +} + +#ifdef CONFIG_SMP + #define XTP_OFFSET 0x1e0008 #define SMP_IRQ_REDIRECTION (1 << 0) #define SMP_IPI_REDIRECTION (1 << 1) -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern struct smp_boot_data { int cpu_count; @@ -39,6 +56,10 @@ extern char no_int_routing __devinitdata; extern cpumask_t cpu_online_map; +extern cpumask_t cpu_core_map[NR_CPUS]; +extern cpumask_t cpu_sibling_map[NR_CPUS]; +extern int smp_num_siblings; +extern int smp_num_cpucores; extern void __iomem *ipi_base_addr; extern unsigned char smp_int_redirect; @@ -90,22 +111,7 @@ writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */ } -static inline unsigned int -hard_smp_processor_id (void) -{ - union { - struct { - unsigned long reserved : 16; - unsigned long eid : 8; - unsigned long id : 8; - unsigned long ignored : 32; - } f; - unsigned long bits; - } lid; - - lid.bits = ia64_getreg(_IA64_REG_CR_LID); - return lid.f.id << 8 | lid.f.eid; -} +#define hard_smp_processor_id() ia64_get_lid() /* Upping and downing of CPUs */ extern int __cpu_disable (void); @@ -122,10 +128,12 @@ extern void smp_send_reschedule (int cpu); extern void lock_ipi_calllock(void); extern void unlock_ipi_calllock(void); +extern void identify_siblings (struct cpuinfo_ia64 *); #else -#define cpu_logical_id(cpuid) 0 +#define cpu_logical_id(i) 0 +#define cpu_physical_id(i) ia64_get_lid() #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_SMP_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/thread_info.h --- a/xen/include/asm-ia64/linux/asm/thread_info.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/thread_info.h Thu Sep 1 18:46:28 2005 @@ -25,7 +25,7 @@ __u32 flags; /* thread_info flags (see TIF_*) */ __u32 cpu; /* current CPU */ mm_segment_t addr_limit; /* user-level address space limit */ - __s32 preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */ + int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */ struct restart_block restart_block; struct { int signo; diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/topology.h --- a/xen/include/asm-ia64/linux/asm/topology.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/topology.h Thu Sep 1 18:46:28 2005 @@ -40,27 +40,61 @@ */ #define node_to_first_cpu(node) (__ffs(node_to_cpumask(node))) +/* + * Determines the node for a given pci bus + */ +#define pcibus_to_node(bus) PCI_CONTROLLER(bus)->node + void build_cpu_to_node_map(void); + +#define SD_CPU_INIT (struct sched_domain) { \ + .span = CPU_MASK_NONE, \ + .parent = NULL, \ + .groups = NULL, \ + .min_interval = 1, \ + .max_interval = 4, \ + .busy_factor = 64, \ + .imbalance_pct = 125, \ + .cache_hot_time = (10*1000000), \ + .per_cpu_gain = 100, \ + .cache_nice_tries = 2, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ + .flags = SD_LOAD_BALANCE \ + | SD_BALANCE_NEWIDLE \ + | SD_BALANCE_EXEC \ + | SD_WAKE_AFFINE, \ + .last_balance = jiffies, \ + .balance_interval = 1, \ + .nr_balance_failed = 0, \ +} /* sched_domains SD_NODE_INIT for IA64 NUMA machines */ #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ .groups = NULL, \ - .min_interval = 80, \ - .max_interval = 320, \ - .busy_factor = 320, \ + .min_interval = 8, \ + .max_interval = 8*(min(num_online_cpus(), 32)), \ + .busy_factor = 64, \ .imbalance_pct = 125, \ .cache_hot_time = (10*1000000), \ - .cache_nice_tries = 1, \ + .cache_nice_tries = 2, \ + .busy_idx = 3, \ + .idle_idx = 2, \ + .newidle_idx = 0, /* unused */ \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ .per_cpu_gain = 100, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_EXEC \ - | SD_BALANCE_NEWIDLE \ - | SD_WAKE_IDLE \ + | SD_BALANCE_FORK \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ - .balance_interval = 1, \ + .balance_interval = 64, \ .nr_balance_failed = 0, \ } @@ -69,17 +103,21 @@ .span = CPU_MASK_NONE, \ .parent = NULL, \ .groups = NULL, \ - .min_interval = 80, \ - .max_interval = 320, \ - .busy_factor = 320, \ - .imbalance_pct = 125, \ + .min_interval = 64, \ + .max_interval = 64*num_online_cpus(), \ + .busy_factor = 128, \ + .imbalance_pct = 133, \ .cache_hot_time = (10*1000000), \ .cache_nice_tries = 1, \ + .busy_idx = 3, \ + .idle_idx = 3, \ + .newidle_idx = 0, /* unused */ \ + .wake_idx = 0, /* unused */ \ + .forkexec_idx = 0, /* unused */ \ .per_cpu_gain = 100, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_EXEC, \ + .flags = SD_LOAD_BALANCE, \ .last_balance = jiffies, \ - .balance_interval = 100*(63+num_online_cpus())/64, \ + .balance_interval = 64, \ .nr_balance_failed = 0, \ } diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/unaligned.h --- a/xen/include/asm-ia64/linux/asm/unaligned.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/unaligned.h Thu Sep 1 18:46:28 2005 @@ -1,121 +1,6 @@ #ifndef _ASM_IA64_UNALIGNED_H #define _ASM_IA64_UNALIGNED_H -#include <linux/types.h> - -/* - * The main single-value unaligned transfer routines. - * - * Based on <asm-alpha/unaligned.h>. - * - * Copyright (C) 1998, 1999, 2003 Hewlett-Packard Co - * David Mosberger-Tang <davidm@xxxxxxxxxx> - */ -#define get_unaligned(ptr) \ - ((__typeof__(*(ptr)))ia64_get_unaligned((ptr), sizeof(*(ptr)))) - -#define put_unaligned(x,ptr) \ - ia64_put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr))) - -struct __una_u64 { __u64 x __attribute__((packed)); }; -struct __una_u32 { __u32 x __attribute__((packed)); }; -struct __una_u16 { __u16 x __attribute__((packed)); }; - -static inline unsigned long -__uld8 (const unsigned long * addr) -{ - const struct __una_u64 *ptr = (const struct __una_u64 *) addr; - return ptr->x; -} - -static inline unsigned long -__uld4 (const unsigned int * addr) -{ - const struct __una_u32 *ptr = (const struct __una_u32 *) addr; - return ptr->x; -} - -static inline unsigned long -__uld2 (const unsigned short * addr) -{ - const struct __una_u16 *ptr = (const struct __una_u16 *) addr; - return ptr->x; -} - -static inline void -__ust8 (unsigned long val, unsigned long * addr) -{ - struct __una_u64 *ptr = (struct __una_u64 *) addr; - ptr->x = val; -} - -static inline void -__ust4 (unsigned long val, unsigned int * addr) -{ - struct __una_u32 *ptr = (struct __una_u32 *) addr; - ptr->x = val; -} - -static inline void -__ust2 (unsigned long val, unsigned short * addr) -{ - struct __una_u16 *ptr = (struct __una_u16 *) addr; - ptr->x = val; -} - - -/* - * This function doesn't actually exist. The idea is that when someone uses the macros - * below with an unsupported size (datatype), the linker will alert us to the problem via - * an unresolved reference error. - */ -extern unsigned long ia64_bad_unaligned_access_length (void); - -#define ia64_get_unaligned(_ptr,size) \ -({ \ - const void *__ia64_ptr = (_ptr); \ - unsigned long __ia64_val; \ - \ - switch (size) { \ - case 1: \ - __ia64_val = *(const unsigned char *) __ia64_ptr; \ - break; \ - case 2: \ - __ia64_val = __uld2((const unsigned short *)__ia64_ptr); \ - break; \ - case 4: \ - __ia64_val = __uld4((const unsigned int *)__ia64_ptr); \ - break; \ - case 8: \ - __ia64_val = __uld8((const unsigned long *)__ia64_ptr); \ - break; \ - default: \ - __ia64_val = ia64_bad_unaligned_access_length(); \ - } \ - __ia64_val; \ -}) - -#define ia64_put_unaligned(_val,_ptr,size) \ -do { \ - const void *__ia64_ptr = (_ptr); \ - unsigned long __ia64_val = (_val); \ - \ - switch (size) { \ - case 1: \ - *(unsigned char *)__ia64_ptr = (__ia64_val); \ - break; \ - case 2: \ - __ust2(__ia64_val, (unsigned short *)__ia64_ptr); \ - break; \ - case 4: \ - __ust4(__ia64_val, (unsigned int *)__ia64_ptr); \ - break; \ - case 8: \ - __ust8(__ia64_val, (unsigned long *)__ia64_ptr); \ - break; \ - default: \ - ia64_bad_unaligned_access_length(); \ - } \ -} while (0) +#include <asm-generic/unaligned.h> #endif /* _ASM_IA64_UNALIGNED_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/unistd.h --- a/xen/include/asm-ia64/linux/asm/unistd.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/unistd.h Thu Sep 1 18:46:28 2005 @@ -263,6 +263,12 @@ #define __NR_add_key 1271 #define __NR_request_key 1272 #define __NR_keyctl 1273 +#define __NR_ioprio_set 1274 +#define __NR_ioprio_get 1275 +#define __NR_set_zone_reclaim 1276 +#define __NR_inotify_init 1277 +#define __NR_inotify_add_watch 1278 +#define __NR_inotify_rm_watch 1279 #ifdef __KERNEL__ @@ -392,7 +398,7 @@ * proper prototype, but we can't use __typeof__ either, because not all cond_syscall() * declarations have prototypes at the moment. */ -#define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall"))); +#define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall"))) #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/bitmap.h --- a/xen/include/asm-ia64/linux/bitmap.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/bitmap.h Thu Sep 1 18:46:28 2005 @@ -41,7 +41,9 @@ * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n * bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf - * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from buf + * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf + * bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf + * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list */ /* @@ -98,6 +100,10 @@ const unsigned long *src, int nbits); extern int bitmap_parse(const char __user *ubuf, unsigned int ulen, unsigned long *dst, int nbits); +extern int bitmap_scnlistprintf(char *buf, unsigned int len, + const unsigned long *src, int nbits); +extern int bitmap_parselist(const char *buf, unsigned long *maskp, + int nmaskbits); extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/bitops.h --- a/xen/include/asm-ia64/linux/bitops.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/bitops.h Thu Sep 1 18:46:28 2005 @@ -134,4 +134,26 @@ return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w); } +/* + * rol32 - rotate a 32-bit value left + * + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +/* + * ror32 - rotate a 32-bit value right + * + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u32 ror32(__u32 word, unsigned int shift) +{ + return (word >> shift) | (word << (32 - shift)); +} + #endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/dma-mapping.h --- a/xen/include/asm-ia64/linux/dma-mapping.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/dma-mapping.h Thu Sep 1 18:46:28 2005 @@ -14,7 +14,12 @@ }; #define DMA_64BIT_MASK 0xffffffffffffffffULL +#define DMA_40BIT_MASK 0x000000ffffffffffULL +#define DMA_39BIT_MASK 0x0000007fffffffffULL #define DMA_32BIT_MASK 0x00000000ffffffffULL +#define DMA_31BIT_MASK 0x000000007fffffffULL +#define DMA_30BIT_MASK 0x000000003fffffffULL +#define DMA_29BIT_MASK 0x000000001fffffffULL #include <asm/dma-mapping.h> diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/efi.h --- a/xen/include/asm-ia64/linux/efi.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/efi.h Thu Sep 1 18:46:28 2005 @@ -301,7 +301,6 @@ extern int __init efi_uart_console_only (void); extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource); -extern efi_status_t phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc); extern unsigned long __init efi_get_time(void); extern int __init efi_set_rtc_mmss(unsigned long nowtime); extern struct efi_memory_map memmap; @@ -316,7 +315,7 @@ */ static inline int efi_range_is_wc(unsigned long start, unsigned long len) { - int i; + unsigned long i; for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { unsigned long paddr = __pa(start + i); diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/err.h --- a/xen/include/asm-ia64/linux/err.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/err.h Thu Sep 1 18:46:28 2005 @@ -13,6 +13,8 @@ * This should be a per-architecture thing, to allow different * error and pointer decisions. */ +#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L) + static inline void *ERR_PTR(long error) { return (void *) error; @@ -25,7 +27,7 @@ static inline long IS_ERR(const void *ptr) { - return unlikely((unsigned long)ptr > (unsigned long)-1000L); + return IS_ERR_VALUE((unsigned long)ptr); } #endif /* _LINUX_ERR_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/gfp.h --- a/xen/include/asm-ia64/linux/gfp.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/gfp.h Thu Sep 1 18:46:28 2005 @@ -12,8 +12,8 @@ * GFP bitmasks.. */ /* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */ -#define __GFP_DMA 0x01 -#define __GFP_HIGHMEM 0x02 +#define __GFP_DMA 0x01u +#define __GFP_HIGHMEM 0x02u /* * Action modifiers - doesn't change the zoning @@ -26,26 +26,29 @@ * * __GFP_NORETRY: The VM implementation must not retry indefinitely. */ -#define __GFP_WAIT 0x10 /* Can wait and reschedule? */ -#define __GFP_HIGH 0x20 /* Should access emergency pools? */ -#define __GFP_IO 0x40 /* Can start physical IO? */ -#define __GFP_FS 0x80 /* Can call down to low-level FS? */ -#define __GFP_COLD 0x100 /* Cache-cold page required */ -#define __GFP_NOWARN 0x200 /* Suppress page allocation failure warning */ -#define __GFP_REPEAT 0x400 /* Retry the allocation. Might fail */ -#define __GFP_NOFAIL 0x800 /* Retry for ever. Cannot fail */ -#define __GFP_NORETRY 0x1000 /* Do not retry. Might fail */ -#define __GFP_NO_GROW 0x2000 /* Slab internal usage */ -#define __GFP_COMP 0x4000 /* Add compound page metadata */ -#define __GFP_ZERO 0x8000 /* Return zeroed page on success */ +#define __GFP_WAIT 0x10u /* Can wait and reschedule? */ +#define __GFP_HIGH 0x20u /* Should access emergency pools? */ +#define __GFP_IO 0x40u /* Can start physical IO? */ +#define __GFP_FS 0x80u /* Can call down to low-level FS? */ +#define __GFP_COLD 0x100u /* Cache-cold page required */ +#define __GFP_NOWARN 0x200u /* Suppress page allocation failure warning */ +#define __GFP_REPEAT 0x400u /* Retry the allocation. Might fail */ +#define __GFP_NOFAIL 0x800u /* Retry for ever. Cannot fail */ +#define __GFP_NORETRY 0x1000u /* Do not retry. Might fail */ +#define __GFP_NO_GROW 0x2000u /* Slab internal usage */ +#define __GFP_COMP 0x4000u /* Add compound page metadata */ +#define __GFP_ZERO 0x8000u /* Return zeroed page on success */ +#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */ +#define __GFP_NORECLAIM 0x20000u /* No realy zone reclaim during allocation */ -#define __GFP_BITS_SHIFT 16 /* Room for 16 __GFP_FOO bits */ +#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) /* if you forget to add the bitmask here kernel will crash, period */ #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \ __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \ - __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP) + __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \ + __GFP_NOMEMALLOC|__GFP_NORECLAIM) #define GFP_ATOMIC (__GFP_HIGH) #define GFP_NOIO (__GFP_WAIT) @@ -82,7 +85,7 @@ extern struct page * FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *)); -static inline struct page *alloc_pages_node(int nid, unsigned int gfp_mask, +static inline struct page *alloc_pages_node(int nid, unsigned int __nocast gfp_mask, unsigned int order) { if (unlikely(order >= MAX_ORDER)) @@ -93,17 +96,17 @@ } #ifdef CONFIG_NUMA -extern struct page *alloc_pages_current(unsigned gfp_mask, unsigned order); +extern struct page *alloc_pages_current(unsigned int __nocast gfp_mask, unsigned order); static inline struct page * -alloc_pages(unsigned int gfp_mask, unsigned int order) +alloc_pages(unsigned int __nocast gfp_mask, unsigned int order) { if (unlikely(order >= MAX_ORDER)) return NULL; return alloc_pages_current(gfp_mask, order); } -extern struct page *alloc_page_vma(unsigned gfp_mask, +extern struct page *alloc_page_vma(unsigned __nocast gfp_mask, struct vm_area_struct *vma, unsigned long addr); #else #define alloc_pages(gfp_mask, order) \ @@ -112,8 +115,8 @@ #endif #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) -extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order)); -extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask)); +extern unsigned long FASTCALL(__get_free_pages(unsigned int __nocast gfp_mask, unsigned int order)); +extern unsigned long FASTCALL(get_zeroed_page(unsigned int __nocast gfp_mask)); #define __get_free_page(gfp_mask) \ __get_free_pages((gfp_mask),0) @@ -130,5 +133,10 @@ #define free_page(addr) free_pages((addr),0) void page_alloc_init(void); +#ifdef CONFIG_NUMA +void drain_remote_pages(void); +#else +static inline void drain_remote_pages(void) { }; +#endif #endif /* __LINUX_GFP_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/mmzone.h --- a/xen/include/asm-ia64/linux/mmzone.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/mmzone.h Thu Sep 1 18:46:28 2005 @@ -11,6 +11,7 @@ #include <linux/cache.h> #include <linux/threads.h> #include <linux/numa.h> +#include <linux/init.h> #include <asm/atomic.h> /* Free memory management - zoned buddy allocator. */ @@ -61,6 +62,12 @@ unsigned long other_node; /* allocation from other node */ #endif } ____cacheline_aligned_in_smp; + +#ifdef CONFIG_NUMA +#define zone_pcp(__z, __cpu) ((__z)->pageset[(__cpu)]) +#else +#define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)]) +#endif #define ZONE_DMA 0 #define ZONE_NORMAL 1 @@ -121,8 +128,11 @@ */ unsigned long lowmem_reserve[MAX_NR_ZONES]; +#ifdef CONFIG_NUMA + struct per_cpu_pageset *pageset[NR_CPUS]; +#else struct per_cpu_pageset pageset[NR_CPUS]; - +#endif /* * free areas of different sizes */ @@ -144,6 +154,14 @@ int all_unreclaimable; /* All pages pinned */ /* + * Does the allocator try to reclaim pages from the zone as soon + * as it fails a watermark_ok() in __alloc_pages? + */ + int reclaim_pages; + /* A count of how many reclaimers are scanning this zone */ + atomic_t reclaim_in_progress; + + /* * prev_priority holds the scanning priority for this zone. It is * defined as the scanning priority at which we achieved our reclaim * target at the previous try_to_free_pages() or balance_pgdat() @@ -251,7 +269,9 @@ struct zone node_zones[MAX_NR_ZONES]; struct zonelist node_zonelists[GFP_ZONETYPES]; int nr_zones; +#ifdef CONFIG_FLAT_NODE_MEM_MAP struct page *node_mem_map; +#endif struct bootmem_data *bdata; unsigned long node_start_pfn; unsigned long node_present_pages; /* total number of physical pages */ @@ -266,6 +286,12 @@ #define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages) #define node_spanned_pages(nid) (NODE_DATA(nid)->node_spanned_pages) +#ifdef CONFIG_FLAT_NODE_MEM_MAP +#define pgdat_page_nr(pgdat, pagenr) ((pgdat)->node_mem_map + (pagenr)) +#else +#define pgdat_page_nr(pgdat, pagenr) pfn_to_page((pgdat)->node_start_pfn + (pagenr)) +#endif +#define nid_page_nr(nid, pagenr) pgdat_page_nr(NODE_DATA(nid),(pagenr)) extern struct pglist_data *pgdat_list; @@ -278,6 +304,16 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, int alloc_type, int can_try_harder, int gfp_high); +#ifdef CONFIG_HAVE_MEMORY_PRESENT +void memory_present(int nid, unsigned long start, unsigned long end); +#else +static inline void memory_present(int nid, unsigned long start, unsigned long end) {} +#endif + +#ifdef CONFIG_NEED_NODE_MEMMAP_SIZE +unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long); +#endif + /* * zone_idx() returns 0 for the ZONE_DMA zone, 1 for the ZONE_NORMAL zone, etc. */ @@ -370,9 +406,9 @@ #include <linux/topology.h> /* Returns the number of the current Node. */ -#define numa_node_id() (cpu_to_node(_smp_processor_id())) - -#ifndef CONFIG_DISCONTIGMEM +#define numa_node_id() (cpu_to_node(raw_smp_processor_id())) + +#ifndef CONFIG_NEED_MULTIPLE_NODES extern struct pglist_data contig_page_data; #define NODE_DATA(nid) (&contig_page_data) @@ -380,35 +416,176 @@ #define MAX_NODES_SHIFT 1 #define pfn_to_nid(pfn) (0) -#else /* CONFIG_DISCONTIGMEM */ +#else /* CONFIG_NEED_MULTIPLE_NODES */ #include <asm/mmzone.h> + +#endif /* !CONFIG_NEED_MULTIPLE_NODES */ + +#ifdef CONFIG_SPARSEMEM +#include <asm/sparsemem.h> +#endif #if BITS_PER_LONG == 32 || defined(ARCH_HAS_ATOMIC_UNSIGNED) /* * with 32 bit page->flags field, we reserve 8 bits for node/zone info. * there are 3 zones (2 bits) and this leaves 8-2=6 bits for nodes. */ -#define MAX_NODES_SHIFT 6 +#define FLAGS_RESERVED 8 + #elif BITS_PER_LONG == 64 /* * with 64 bit flags field, there's plenty of room. */ -#define MAX_NODES_SHIFT 10 -#endif - -#endif /* !CONFIG_DISCONTIGMEM */ - -#if NODES_SHIFT > MAX_NODES_SHIFT -#error NODES_SHIFT > MAX_NODES_SHIFT -#endif - -/* There are currently 3 zones: DMA, Normal & Highmem, thus we need 2 bits */ -#define MAX_ZONES_SHIFT 2 - -#if ZONES_SHIFT > MAX_ZONES_SHIFT -#error ZONES_SHIFT > MAX_ZONES_SHIFT -#endif +#define FLAGS_RESERVED 32 + +#else + +#error BITS_PER_LONG not defined + +#endif + +#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID +#define early_pfn_to_nid(nid) (0UL) +#endif + +#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT) +#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT) + +#ifdef CONFIG_SPARSEMEM + +/* + * SECTION_SHIFT #bits space required to store a section # + * + * PA_SECTION_SHIFT physical address to/from section number + * PFN_SECTION_SHIFT pfn to/from section number + */ +#define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS) + +#define PA_SECTION_SHIFT (SECTION_SIZE_BITS) +#define PFN_SECTION_SHIFT (SECTION_SIZE_BITS - PAGE_SHIFT) + +#define NR_MEM_SECTIONS (1UL << SECTIONS_SHIFT) + +#define PAGES_PER_SECTION (1UL << PFN_SECTION_SHIFT) +#define PAGE_SECTION_MASK (~(PAGES_PER_SECTION-1)) + +#if (MAX_ORDER - 1 + PAGE_SHIFT) > SECTION_SIZE_BITS +#error Allocator MAX_ORDER exceeds SECTION_SIZE +#endif + +struct page; +struct mem_section { + /* + * This is, logically, a pointer to an array of struct + * pages. However, it is stored with some other magic. + * (see sparse.c::sparse_init_one_section()) + * + * Making it a UL at least makes someone do a cast + * before using it wrong. + */ + unsigned long section_mem_map; +}; + +extern struct mem_section mem_section[NR_MEM_SECTIONS]; + +static inline struct mem_section *__nr_to_section(unsigned long nr) +{ + return &mem_section[nr]; +} + +/* + * We use the lower bits of the mem_map pointer to store + * a little bit of information. There should be at least + * 3 bits here due to 32-bit alignment. + */ +#define SECTION_MARKED_PRESENT (1UL<<0) +#define SECTION_HAS_MEM_MAP (1UL<<1) +#define SECTION_MAP_LAST_BIT (1UL<<2) +#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1)) + +static inline struct page *__section_mem_map_addr(struct mem_section *section) +{ + unsigned long map = section->section_mem_map; + map &= SECTION_MAP_MASK; + return (struct page *)map; +} + +static inline int valid_section(struct mem_section *section) +{ + return (section->section_mem_map & SECTION_MARKED_PRESENT); +} + +static inline int section_has_mem_map(struct mem_section *section) +{ + return (section->section_mem_map & SECTION_HAS_MEM_MAP); +} + +static inline int valid_section_nr(unsigned long nr) +{ + return valid_section(__nr_to_section(nr)); +} + +/* + * Given a kernel address, find the home node of the underlying memory. + */ +#define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT) + +static inline struct mem_section *__pfn_to_section(unsigned long pfn) +{ + return __nr_to_section(pfn_to_section_nr(pfn)); +} + +#define pfn_to_page(pfn) \ +({ \ + unsigned long __pfn = (pfn); \ + __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \ +}) +#define page_to_pfn(page) \ +({ \ + page - __section_mem_map_addr(__nr_to_section( \ + page_to_section(page))); \ +}) + +static inline int pfn_valid(unsigned long pfn) +{ + if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) + return 0; + return valid_section(__nr_to_section(pfn_to_section_nr(pfn))); +} + +/* + * These are _only_ used during initialisation, therefore they + * can use __initdata ... They could have names to indicate + * this restriction. + */ +#ifdef CONFIG_NUMA +#define pfn_to_nid early_pfn_to_nid +#endif + +#define pfn_to_pgdat(pfn) \ +({ \ + NODE_DATA(pfn_to_nid(pfn)); \ +}) + +#define early_pfn_valid(pfn) pfn_valid(pfn) +void sparse_init(void); +#else +#define sparse_init() do {} while (0) +#endif /* CONFIG_SPARSEMEM */ + +#ifdef CONFIG_NODES_SPAN_OTHER_NODES +#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid)) +#else +#define early_pfn_in_nid(pfn, nid) (1) +#endif + +#ifndef early_pfn_valid +#define early_pfn_valid(pfn) (1) +#endif + +void memory_present(int nid, unsigned long start, unsigned long end); +unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long); #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/numa.h --- a/xen/include/asm-ia64/linux/numa.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/numa.h Thu Sep 1 18:46:28 2005 @@ -3,7 +3,7 @@ #include <linux/config.h> -#ifdef CONFIG_DISCONTIGMEM +#ifndef CONFIG_FLATMEM #include <asm/numnodes.h> #endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/page-flags.h --- a/xen/include/asm-ia64/linux/page-flags.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/page-flags.h Thu Sep 1 18:46:28 2005 @@ -61,21 +61,20 @@ #define PG_active 6 #define PG_slab 7 /* slab debug (Suparna wants this) */ -#define PG_highmem 8 -#define PG_checked 9 /* kill me in 2.5.<early>. */ -#define PG_arch_1 10 -#define PG_reserved 11 - -#define PG_private 12 /* Has something at ->private */ -#define PG_writeback 13 /* Page is under writeback */ -#define PG_nosave 14 /* Used for system suspend/resume */ -#define PG_compound 15 /* Part of a compound page */ - -#define PG_swapcache 16 /* Swap page: swp_entry_t in private */ -#define PG_mappedtodisk 17 /* Has blocks allocated on-disk */ -#define PG_reclaim 18 /* To be reclaimed asap */ -#define PG_nosave_free 19 /* Free, should not be written */ - +#define PG_checked 8 /* kill me in 2.5.<early>. */ +#define PG_arch_1 9 +#define PG_reserved 10 +#define PG_private 11 /* Has something at ->private */ + +#define PG_writeback 12 /* Page is under writeback */ +#define PG_nosave 13 /* Used for system suspend/resume */ +#define PG_compound 14 /* Part of a compound page */ +#define PG_swapcache 15 /* Swap page: swp_entry_t in private */ + +#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ +#define PG_reclaim 17 /* To be reclaimed asap */ +#define PG_nosave_free 18 /* Free, should not be written */ +#define PG_uncached 19 /* Page has been mapped as uncached */ /* * Global page accounting. One instance per CPU. Only unsigned longs are @@ -131,12 +130,13 @@ unsigned long allocstall; /* direct reclaim calls */ unsigned long pgrotated; /* pages rotated to tail of the LRU */ + unsigned long nr_bounce; /* pages for bounce buffers */ }; extern void get_page_state(struct page_state *ret); extern void get_full_page_state(struct page_state *ret); -extern unsigned long __read_page_state(unsigned offset); -extern void __mod_page_state(unsigned offset, unsigned long delta); +extern unsigned long __read_page_state(unsigned long offset); +extern void __mod_page_state(unsigned long offset, unsigned long delta); #define read_page_state(member) \ __read_page_state(offsetof(struct page_state, member)) @@ -214,7 +214,7 @@ #define TestSetPageSlab(page) test_and_set_bit(PG_slab, &(page)->flags) #ifdef CONFIG_HIGHMEM -#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) +#define PageHighMem(page) is_highmem(page_zone(page)) #else #define PageHighMem(page) 0 /* needed to optimize away at compile time */ #endif @@ -301,10 +301,13 @@ #define PageSwapCache(page) 0 #endif +#define PageUncached(page) test_bit(PG_uncached, &(page)->flags) +#define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags) +#define ClearPageUncached(page) clear_bit(PG_uncached, &(page)->flags) + struct page; /* forward declaration */ int test_clear_page_dirty(struct page *page); -int __clear_page_dirty(struct page *page); int test_clear_page_writeback(struct page *page); int test_set_page_writeback(struct page *page); diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/slab.h --- a/xen/include/asm-ia64/linux/slab.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/slab.h Thu Sep 1 18:46:28 2005 @@ -1,3 +1,137 @@ -#include <xen/xmalloc.h> -#include <linux/gfp.h> -#include <asm/delay.h> +/* + * linux/mm/slab.h + * Written by Mark Hemment, 1996. + * (markhe@xxxxxxxxxxxxxxxxx) + */ + +#ifndef _LINUX_SLAB_H +#define _LINUX_SLAB_H + +#if defined(__KERNEL__) + +typedef struct kmem_cache_s kmem_cache_t; + +#include <linux/config.h> /* kmalloc_sizes.h needs CONFIG_ options */ +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/types.h> +#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */ +#include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */ + +/* flags for kmem_cache_alloc() */ +#define SLAB_NOFS GFP_NOFS +#define SLAB_NOIO GFP_NOIO +#define SLAB_ATOMIC GFP_ATOMIC +#define SLAB_USER GFP_USER +#define SLAB_KERNEL GFP_KERNEL +#define SLAB_DMA GFP_DMA + +#define SLAB_LEVEL_MASK GFP_LEVEL_MASK + +#define SLAB_NO_GROW __GFP_NO_GROW /* don't grow a cache */ + +/* flags to pass to kmem_cache_create(). + * The first 3 are only valid when the allocator as been build + * SLAB_DEBUG_SUPPORT. + */ +#define SLAB_DEBUG_FREE 0x00000100UL /* Peform (expensive) checks on free */ +#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor (as verifier) */ +#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */ +#define SLAB_POISON 0x00000800UL /* Poison objects */ +#define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */ +#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */ +#define SLAB_CACHE_DMA 0x00004000UL /* use GFP_DMA memory */ +#define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* force alignment */ +#define SLAB_STORE_USER 0x00010000UL /* store the last owner for bug hunting */ +#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* track pages allocated to indicate + what is reclaimable later*/ +#define SLAB_PANIC 0x00040000UL /* panic if kmem_cache_create() fails */ +#define SLAB_DESTROY_BY_RCU 0x00080000UL /* defer freeing pages to RCU */ + +/* flags passed to a constructor func */ +#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */ +#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */ +#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */ + +/* prototypes */ +extern void __init kmem_cache_init(void); + +extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, + void (*)(void *, kmem_cache_t *, unsigned long), + void (*)(void *, kmem_cache_t *, unsigned long)); +extern int kmem_cache_destroy(kmem_cache_t *); +extern int kmem_cache_shrink(kmem_cache_t *); +extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast); +extern void kmem_cache_free(kmem_cache_t *, void *); +extern unsigned int kmem_cache_size(kmem_cache_t *); +extern const char *kmem_cache_name(kmem_cache_t *); +extern kmem_cache_t *kmem_find_general_cachep(size_t size, unsigned int __nocast gfpflags); + +/* Size description struct for general caches. */ +struct cache_sizes { + size_t cs_size; + kmem_cache_t *cs_cachep; + kmem_cache_t *cs_dmacachep; +}; +extern struct cache_sizes malloc_sizes[]; +extern void *__kmalloc(size_t, unsigned int __nocast); + +static inline void *kmalloc(size_t size, unsigned int __nocast flags) +{ + if (__builtin_constant_p(size)) { + int i = 0; +#define CACHE(x) \ + if (size <= x) \ + goto found; \ + else \ + i++; +#include "kmalloc_sizes.h" +#undef CACHE + { + extern void __you_cannot_kmalloc_that_much(void); + __you_cannot_kmalloc_that_much(); + } +found: + return kmem_cache_alloc((flags & GFP_DMA) ? + malloc_sizes[i].cs_dmacachep : + malloc_sizes[i].cs_cachep, flags); + } + return __kmalloc(size, flags); +} + +extern void *kcalloc(size_t, size_t, unsigned int __nocast); +extern void kfree(const void *); +extern unsigned int ksize(const void *); + +#ifdef CONFIG_NUMA +extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node); +extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node); +#else +static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node) +{ + return kmem_cache_alloc(cachep, flags); +} +static inline void *kmalloc_node(size_t size, unsigned int __nocast flags, int node) +{ + return kmalloc(size, flags); +} +#endif + +extern int FASTCALL(kmem_cache_reap(int)); +extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)); + +/* System wide caches */ +extern kmem_cache_t *vm_area_cachep; +extern kmem_cache_t *names_cachep; +extern kmem_cache_t *files_cachep; +extern kmem_cache_t *filp_cachep; +extern kmem_cache_t *fs_cachep; +extern kmem_cache_t *signal_cachep; +extern kmem_cache_t *sighand_cachep; +extern kmem_cache_t *bio_cachep; + +extern atomic_t slab_reclaim_pages; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SLAB_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/threads.h --- a/xen/include/asm-ia64/linux/threads.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/threads.h Thu Sep 1 18:46:28 2005 @@ -7,7 +7,7 @@ * The default limit for the nr of threads is now in * /proc/sys/kernel/threads-max. */ - + /* * Maximum supported processors that can run under SMP. This value is * set via configure setting. The maximum is equal to the size of the @@ -25,11 +25,12 @@ /* * This controls the default maximum pid allocated to a process */ -#define PID_MAX_DEFAULT 0x8000 +#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) /* * A maximum of 4 million PIDs should be enough for a while: */ -#define PID_MAX_LIMIT (sizeof(long) > 4 ? 4*1024*1024 : PID_MAX_DEFAULT) +#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ + (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) #endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/timex.h --- a/xen/include/asm-ia64/linux/timex.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/timex.h Thu Sep 1 18:46:28 2005 @@ -240,9 +240,7 @@ extern long time_maxerror; /* maximum error */ extern long time_esterror; /* estimated error */ -extern long time_phase; /* phase offset (scaled us) */ extern long time_freq; /* frequency offset (scaled ppm) */ -extern long time_adj; /* tick adjust (scaled 1 / HZ) */ extern long time_reftime; /* time at last adjustment (s) */ extern long time_adjust; /* The amount of adjtime left */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/topology.h --- a/xen/include/asm-ia64/linux/topology.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/topology.h Thu Sep 1 18:46:28 2005 @@ -31,8 +31,11 @@ #include <linux/bitops.h> #include <linux/mmzone.h> #include <linux/smp.h> +#include <asm/topology.h> -#include <asm/topology.h> +#ifndef node_has_online_mem +#define node_has_online_mem(nid) (1) +#endif #ifndef nr_cpus_node #define nr_cpus_node(node) \ @@ -86,6 +89,11 @@ .cache_hot_time = 0, \ .cache_nice_tries = 0, \ .per_cpu_gain = 25, \ + .busy_idx = 0, \ + .idle_idx = 0, \ + .newidle_idx = 1, \ + .wake_idx = 0, \ + .forkexec_idx = 0, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ @@ -112,12 +120,15 @@ .cache_hot_time = (5*1000000/2), \ .cache_nice_tries = 1, \ .per_cpu_gain = 100, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ - | SD_WAKE_AFFINE \ - | SD_WAKE_IDLE \ - | SD_WAKE_BALANCE, \ + | SD_WAKE_AFFINE, \ .last_balance = jiffies, \ .balance_interval = 1, \ .nr_balance_failed = 0, \ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/wait.h --- a/xen/include/asm-ia64/linux/wait.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/wait.h Thu Sep 1 18:46:28 2005 @@ -33,7 +33,7 @@ struct __wait_queue { unsigned int flags; #define WQ_FLAG_EXCLUSIVE 0x01 - struct task_struct * task; + void *private; wait_queue_func_t func; struct list_head task_list; }; @@ -60,7 +60,7 @@ */ #define __WAITQUEUE_INITIALIZER(name, tsk) { \ - .task = tsk, \ + .private = tsk, \ .func = default_wake_function, \ .task_list = { NULL, NULL } } @@ -79,14 +79,14 @@ static inline void init_waitqueue_head(wait_queue_head_t *q) { - q->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&q->lock); INIT_LIST_HEAD(&q->task_list); } static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) { q->flags = 0; - q->task = p; + q->private = p; q->func = default_wake_function; } @@ -94,7 +94,7 @@ wait_queue_func_t func) { q->flags = 0; - q->task = NULL; + q->private = NULL; q->func = func; } @@ -110,7 +110,7 @@ * aio specifies a wait queue entry with an async notification * callback routine, not associated with any task. */ -#define is_sync_wait(wait) (!(wait) || ((wait)->task)) +#define is_sync_wait(wait) (!(wait) || ((wait)->private)) extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); @@ -169,6 +169,18 @@ finish_wait(&wq, &__wait); \ } while (0) +/** + * wait_event - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + */ #define wait_event(wq, condition) \ do { \ if (condition) \ @@ -191,6 +203,22 @@ finish_wait(&wq, &__wait); \ } while (0) +/** + * wait_event_timeout - sleep until a condition gets true or a timeout elapses + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * @timeout: timeout, in jiffies + * + * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function returns 0 if the @timeout elapsed, and the remaining + * jiffies if the condition evaluated to true before the timeout elapsed. + */ #define wait_event_timeout(wq, condition, timeout) \ ({ \ long __ret = timeout; \ @@ -217,6 +245,21 @@ finish_wait(&wq, &__wait); \ } while (0) +/** + * wait_event_interruptible - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function will return -ERESTARTSYS if it was interrupted by a + * signal and 0 if @condition evaluated to true. + */ #define wait_event_interruptible(wq, condition) \ ({ \ int __ret = 0; \ @@ -245,6 +288,23 @@ finish_wait(&wq, &__wait); \ } while (0) +/** + * wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * @timeout: timeout, in jiffies + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it + * was interrupted by a signal, and the remaining jiffies otherwise + * if the condition evaluated to true before the timeout elapsed. + */ #define wait_event_interruptible_timeout(wq, condition, timeout) \ ({ \ long __ret = timeout; \ @@ -324,18 +384,16 @@ #define DEFINE_WAIT(name) \ wait_queue_t name = { \ - .task = current, \ + .private = current, \ .func = autoremove_wake_function, \ - .task_list = { .next = &(name).task_list, \ - .prev = &(name).task_list, \ - }, \ + .task_list = LIST_HEAD_INIT((name).task_list), \ } #define DEFINE_WAIT_BIT(name, word, bit) \ struct wait_bit_queue name = { \ .key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \ .wait = { \ - .task = current, \ + .private = current, \ .func = wake_bit_function, \ .task_list = \ LIST_HEAD_INIT((name).wait.task_list), \ @@ -344,7 +402,7 @@ #define init_wait(wait) \ do { \ - (wait)->task = current; \ + (wait)->private = current; \ (wait)->func = autoremove_wake_function; \ INIT_LIST_HEAD(&(wait)->task_list); \ } while (0) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/mm.h --- a/xen/include/asm-ia64/mm.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/mm.h Thu Sep 1 18:46:28 2005 @@ -316,6 +316,7 @@ #define VM_STACK_FLAGS (VM_GROWSDOWN | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT) #endif +#if 0 /* removed when rebasing to 2.6.13 */ /* * The zone field is never updated after free_area_init_core() * sets it, so none of the operations on it need to be atomic. @@ -347,6 +348,7 @@ page->flags &= ~(~0UL << NODEZONE_SHIFT); page->flags |= nodezone_num << NODEZONE_SHIFT; } +#endif #ifndef CONFIG_DISCONTIGMEM /* Don't use mapnrs, do it properly */ extern unsigned long max_mapnr; diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/time.h --- a/xen/include/asm-ia64/time.h Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/time.h Thu Sep 1 18:46:28 2005 @@ -1,1 +1,1 @@ -#include <xen/linuxtime.h> +#include <asm/linux/time.h> diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/bitop.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/bitop.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,88 @@ +#include <linux/compiler.h> +#include <linux/types.h> +#include <asm/intrinsics.h> +#include <linux/module.h> +#include <linux/bitops.h> + +/* + * Find next zero bit in a bitmap reasonably efficiently.. + */ + +int __find_next_zero_bit (const void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (64-offset); + if (size < 64) + goto found_first; + if (~tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; +found_first: + tmp |= ~0UL << size; + if (tmp == ~0UL) /* any bits zero? */ + return result + size; /* nope */ +found_middle: + return result + ffz(tmp); +} +EXPORT_SYMBOL(__find_next_zero_bit); + +/* + * Find next bit in a bitmap reasonably efficiently.. + */ +int __find_next_bit(const void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp &= ~0UL << offset; + if (size < 64) + goto found_first; + if (tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if ((tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; + found_first: + tmp &= ~0UL >> (64-size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ + found_middle: + return result + __ffs(tmp); +} +EXPORT_SYMBOL(__find_next_bit); diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/clear_page.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/clear_page.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 1999-2002 Hewlett-Packard Co + * Stephane Eranian <eranian@xxxxxxxxxx> + * David Mosberger-Tang <davidm@xxxxxxxxxx> + * Copyright (C) 2002 Ken Chen <kenneth.w.chen@xxxxxxxxx> + * + * 1/06/01 davidm Tuned for Itanium. + * 2/12/02 kchen Tuned for both Itanium and McKinley + * 3/08/02 davidm Some more tweaking + */ +#include <linux/config.h> + +#include <asm/asmmacro.h> +#include <asm/page.h> + +#ifdef CONFIG_ITANIUM +# define L3_LINE_SIZE 64 // Itanium L3 line size +# define PREFETCH_LINES 9 // magic number +#else +# define L3_LINE_SIZE 128 // McKinley L3 line size +# define PREFETCH_LINES 12 // magic number +#endif + +#define saved_lc r2 +#define dst_fetch r3 +#define dst1 r8 +#define dst2 r9 +#define dst3 r10 +#define dst4 r11 + +#define dst_last r31 + +GLOBAL_ENTRY(clear_page) + .prologue + .regstk 1,0,0,0 + mov r16 = PAGE_SIZE/L3_LINE_SIZE-1 // main loop count, -1=repeat/until + .save ar.lc, saved_lc + mov saved_lc = ar.lc + + .body + mov ar.lc = (PREFETCH_LINES - 1) + mov dst_fetch = in0 + adds dst1 = 16, in0 + adds dst2 = 32, in0 + ;; +.fetch: stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE + adds dst3 = 48, in0 // executing this multiple times is harmless + br.cloop.sptk.few .fetch + ;; + addl dst_last = (PAGE_SIZE - PREFETCH_LINES*L3_LINE_SIZE), dst_fetch + mov ar.lc = r16 // one L3 line per iteration + adds dst4 = 64, in0 + ;; +#ifdef CONFIG_ITANIUM + // Optimized for Itanium +1: stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 + cmp.lt p8,p0=dst_fetch, dst_last + ;; +#else + // Optimized for McKinley +1: stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 + stf.spill.nta [dst3] = f0, 64 + stf.spill.nta [dst4] = f0, 128 + cmp.lt p8,p0=dst_fetch, dst_last + ;; + stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 +#endif + stf.spill.nta [dst3] = f0, 64 +(p8) stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE + br.cloop.sptk.few 1b + ;; + mov ar.lc = saved_lc // restore lc + br.ret.sptk.many rp +END(clear_page) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/copy_page_mck.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/copy_page_mck.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,185 @@ +/* + * McKinley-optimized version of copy_page(). + * + * Copyright (C) 2002 Hewlett-Packard Co + * David Mosberger <davidm@xxxxxxxxxx> + * + * Inputs: + * in0: address of target page + * in1: address of source page + * Output: + * no return value + * + * General idea: + * - use regular loads and stores to prefetch data to avoid consuming M-slot just for + * lfetches => good for in-cache performance + * - avoid l2 bank-conflicts by not storing into the same 16-byte bank within a single + * cycle + * + * Principle of operation: + * First, note that L1 has a line-size of 64 bytes and L2 a line-size of 128 bytes. + * To avoid secondary misses in L2, we prefetch both source and destination with a line-size + * of 128 bytes. When both of these lines are in the L2 and the first half of the + * source line is in L1, we start copying the remaining words. The second half of the + * source line is prefetched in an earlier iteration, so that by the time we start + * accessing it, it's also present in the L1. + * + * We use a software-pipelined loop to control the overall operation. The pipeline + * has 2*PREFETCH_DIST+K stages. The first PREFETCH_DIST stages are used for prefetching + * source cache-lines. The second PREFETCH_DIST stages are used for prefetching destination + * cache-lines, the last K stages are used to copy the cache-line words not copied by + * the prefetches. The four relevant points in the pipelined are called A, B, C, D: + * p[A] is TRUE if a source-line should be prefetched, p[B] is TRUE if a destination-line + * should be prefetched, p[C] is TRUE if the second half of an L2 line should be brought + * into L1D and p[D] is TRUE if a cacheline needs to be copied. + * + * This all sounds very complicated, but thanks to the modulo-scheduled loop support, + * the resulting code is very regular and quite easy to follow (once you get the idea). + * + * As a secondary optimization, the first 2*PREFETCH_DIST iterations are implemented + * as the separate .prefetch_loop. Logically, this loop performs exactly like the + * main-loop (.line_copy), but has all known-to-be-predicated-off instructions removed, + * so that each loop iteration is faster (again, good for cached case). + * + * When reading the code, it helps to keep the following picture in mind: + * + * word 0 word 1 + * +------+------+--- + * | v[x] | t1 | ^ + * | t2 | t3 | | + * | t4 | t5 | | + * | t6 | t7 | | 128 bytes + * | n[y] | t9 | | (L2 cache line) + * | t10 | t11 | | + * | t12 | t13 | | + * | t14 | t15 | v + * +------+------+--- + * + * Here, v[x] is copied by the (memory) prefetch. n[y] is loaded at p[C] + * to fetch the second-half of the L2 cache line into L1, and the tX words are copied in + * an order that avoids bank conflicts. + */ +#include <asm/asmmacro.h> +#include <asm/page.h> + +#define PREFETCH_DIST 8 // McKinley sustains 16 outstanding L2 misses (8 ld, 8 st) + +#define src0 r2 +#define src1 r3 +#define dst0 r9 +#define dst1 r10 +#define src_pre_mem r11 +#define dst_pre_mem r14 +#define src_pre_l2 r15 +#define dst_pre_l2 r16 +#define t1 r17 +#define t2 r18 +#define t3 r19 +#define t4 r20 +#define t5 t1 // alias! +#define t6 t2 // alias! +#define t7 t3 // alias! +#define t9 t5 // alias! +#define t10 t4 // alias! +#define t11 t7 // alias! +#define t12 t6 // alias! +#define t14 t10 // alias! +#define t13 r21 +#define t15 r22 + +#define saved_lc r23 +#define saved_pr r24 + +#define A 0 +#define B (PREFETCH_DIST) +#define C (B + PREFETCH_DIST) +#define D (C + 3) +#define N (D + 1) +#define Nrot ((N + 7) & ~7) + +GLOBAL_ENTRY(copy_page) + .prologue + alloc r8 = ar.pfs, 2, Nrot-2, 0, Nrot + + .rotr v[2*PREFETCH_DIST], n[D-C+1] + .rotp p[N] + + .save ar.lc, saved_lc + mov saved_lc = ar.lc + .save pr, saved_pr + mov saved_pr = pr + .body + + mov src_pre_mem = in1 + mov pr.rot = 0x10000 + mov ar.ec = 1 // special unrolled loop + + mov dst_pre_mem = in0 + mov ar.lc = 2*PREFETCH_DIST - 1 + + add src_pre_l2 = 8*8, in1 + add dst_pre_l2 = 8*8, in0 + add src0 = 8, in1 // first t1 src + add src1 = 3*8, in1 // first t3 src + add dst0 = 8, in0 // first t1 dst + add dst1 = 3*8, in0 // first t3 dst + mov t1 = (PAGE_SIZE/128) - (2*PREFETCH_DIST) - 1 + nop.m 0 + nop.i 0 + ;; + // same as .line_copy loop, but with all predicated-off instructions removed: +.prefetch_loop: +(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 +(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 + br.ctop.sptk .prefetch_loop + ;; + cmp.eq p16, p0 = r0, r0 // reset p16 to 1 (br.ctop cleared it to zero) + mov ar.lc = t1 // with 64KB pages, t1 is too big to fit in 8 bits! + mov ar.ec = N // # of stages in pipeline + ;; +.line_copy: +(p[D]) ld8 t2 = [src0], 3*8 // M0 +(p[D]) ld8 t4 = [src1], 3*8 // M1 +(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 prefetch dst from memory +(p[D]) st8 [dst_pre_l2] = n[D-C], 128 // M3 prefetch dst from L2 + ;; +(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 prefetch src from memory +(p[C]) ld8 n[0] = [src_pre_l2], 128 // M1 prefetch src from L2 +(p[D]) st8 [dst0] = t1, 8 // M2 +(p[D]) st8 [dst1] = t3, 8 // M3 + ;; +(p[D]) ld8 t5 = [src0], 8 +(p[D]) ld8 t7 = [src1], 3*8 +(p[D]) st8 [dst0] = t2, 3*8 +(p[D]) st8 [dst1] = t4, 3*8 + ;; +(p[D]) ld8 t6 = [src0], 3*8 +(p[D]) ld8 t10 = [src1], 8 +(p[D]) st8 [dst0] = t5, 8 +(p[D]) st8 [dst1] = t7, 3*8 + ;; +(p[D]) ld8 t9 = [src0], 3*8 +(p[D]) ld8 t11 = [src1], 3*8 +(p[D]) st8 [dst0] = t6, 3*8 +(p[D]) st8 [dst1] = t10, 8 + ;; +(p[D]) ld8 t12 = [src0], 8 +(p[D]) ld8 t14 = [src1], 8 +(p[D]) st8 [dst0] = t9, 3*8 +(p[D]) st8 [dst1] = t11, 3*8 + ;; +(p[D]) ld8 t13 = [src0], 4*8 +(p[D]) ld8 t15 = [src1], 4*8 +(p[D]) st8 [dst0] = t12, 8 +(p[D]) st8 [dst1] = t14, 8 + ;; +(p[D-1])ld8 t1 = [src0], 8 +(p[D-1])ld8 t3 = [src1], 8 +(p[D]) st8 [dst0] = t13, 4*8 +(p[D]) st8 [dst1] = t15, 4*8 + br.ctop.sptk .line_copy + ;; + mov ar.lc = saved_lc + mov pr = saved_pr, -1 + br.ret.sptk.many rp +END(copy_page) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/flush.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/flush.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,61 @@ +/* + * Cache flushing routines. + * + * Copyright (C) 1999-2001, 2005 Hewlett-Packard Co + * David Mosberger-Tang <davidm@xxxxxxxxxx> + * + * 05/28/05 Zoltan Menyhart Dynamic stride size + */ + +#include <asm/asmmacro.h> + + + /* + * flush_icache_range(start,end) + * + * Make i-cache(s) coherent with d-caches. + * + * Must deal with range from start to end-1 but nothing else (need to + * be careful not to touch addresses that may be unmapped). + * + * Note: "in0" and "in1" are preserved for debugging purposes. + */ +GLOBAL_ENTRY(flush_icache_range) + + .prologue + alloc r2=ar.pfs,2,0,0,0 + movl r3=ia64_i_cache_stride_shift + mov r21=1 + ;; + ld8 r20=[r3] // r20: stride shift + sub r22=in1,r0,1 // last byte address + ;; + shr.u r23=in0,r20 // start / (stride size) + shr.u r22=r22,r20 // (last byte address) / (stride size) + shl r21=r21,r20 // r21: stride size of the i-cache(s) + ;; + sub r8=r22,r23 // number of strides - 1 + shl r24=r23,r20 // r24: addresses for "fc.i" = + // "start" rounded down to stride boundary + .save ar.lc,r3 + mov r3=ar.lc // save ar.lc + ;; + + .body + mov ar.lc=r8 + ;; + /* + * 32 byte aligned loop, even number of (actually 2) bundles + */ +.Loop: fc.i r24 // issuable on M0 only + add r24=r21,r24 // we flush "stride size" bytes per iteration + nop.i 0 + br.cloop.sptk.few .Loop + ;; + sync.i + ;; + srlz.i + ;; + mov ar.lc=r3 // restore ar.lc + br.ret.sptk.many rp +END(flush_icache_range) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/idiv32.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/idiv32.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang <davidm@xxxxxxxxxx> + * + * 32-bit integer division. + * + * This code is based on the application note entitled "Divide, Square Root + * and Remainder Algorithms for the IA-64 Architecture". This document + * is available as Intel document number 248725-002 or via the web at + * http://developer.intel.com/software/opensource/numerics/ + * + * For more details on the theory behind these algorithms, see "IA-64 + * and Elementary Functions" by Peter Markstein; HP Professional Books + * (http://www.hp.com/go/retailbooks/) + */ + +#include <asm/asmmacro.h> + +#ifdef MODULO +# define OP mod +#else +# define OP div +#endif + +#ifdef UNSIGNED +# define SGN u +# define EXTEND zxt4 +# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b +# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b +#else +# define SGN +# define EXTEND sxt4 +# define INT_TO_FP(a,b) fcvt.xf a=b +# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b +#endif + +#define PASTE1(a,b) a##b +#define PASTE(a,b) PASTE1(a,b) +#define NAME PASTE(PASTE(__,SGN),PASTE(OP,si3)) + +GLOBAL_ENTRY(NAME) + .regstk 2,0,0,0 + // Transfer inputs to FP registers. + mov r2 = 0xffdd // r2 = -34 + 65535 (fp reg format bias) + EXTEND in0 = in0 // in0 = a + EXTEND in1 = in1 // in1 = b + ;; + setf.sig f8 = in0 + setf.sig f9 = in1 +#ifdef MODULO + sub in1 = r0, in1 // in1 = -b +#endif + ;; + // Convert the inputs to FP, to avoid FP software-assist faults. + INT_TO_FP(f8, f8) + INT_TO_FP(f9, f9) + ;; + setf.exp f7 = r2 // f7 = 2^-34 + frcpa.s1 f6, p6 = f8, f9 // y0 = frcpa(b) + ;; +(p6) fmpy.s1 f8 = f8, f6 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f6, f1 // e0 = -b*y0 + 1 + ;; +#ifdef MODULO + setf.sig f9 = in1 // f9 = -b +#endif +(p6) fma.s1 f8 = f6, f8, f8 // q1 = e0*q0 + q0 +(p6) fma.s1 f6 = f6, f6, f7 // e1 = e0*e0 + 2^-34 + ;; +#ifdef MODULO + setf.sig f7 = in0 +#endif +(p6) fma.s1 f6 = f6, f8, f8 // q2 = e1*q1 + q1 + ;; + FP_TO_INT(f6, f6) // q = trunc(q2) + ;; +#ifdef MODULO + xma.l f6 = f6, f9, f7 // r = q*(-b) + a + ;; +#endif + getf.sig r8 = f6 // transfer result to result register + br.ret.sptk.many rp +END(NAME) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/idiv64.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/idiv64.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@xxxxxxxxxx> + * + * 64-bit integer division. + * + * This code is based on the application note entitled "Divide, Square Root + * and Remainder Algorithms for the IA-64 Architecture". This document + * is available as Intel document number 248725-002 or via the web at + * http://developer.intel.com/software/opensource/numerics/ + * + * For more details on the theory behind these algorithms, see "IA-64 + * and Elementary Functions" by Peter Markstein; HP Professional Books + * (http://www.hp.com/go/retailbooks/) + */ + +#include <asm/asmmacro.h> + +#ifdef MODULO +# define OP mod +#else +# define OP div +#endif + +#ifdef UNSIGNED +# define SGN u +# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b +# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b +#else +# define SGN +# define INT_TO_FP(a,b) fcvt.xf a=b +# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b +#endif + +#define PASTE1(a,b) a##b +#define PASTE(a,b) PASTE1(a,b) +#define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) + +GLOBAL_ENTRY(NAME) + .regstk 2,0,0,0 + // Transfer inputs to FP registers. + setf.sig f8 = in0 + setf.sig f9 = in1 + ;; + // Convert the inputs to FP, to avoid FP software-assist faults. + INT_TO_FP(f8, f8) + INT_TO_FP(f9, f9) + ;; + frcpa.s1 f11, p6 = f8, f9 // y0 = frcpa(b) + ;; +(p6) fmpy.s1 f7 = f8, f11 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f11, f1 // e0 = -b*y0 + 1 + ;; +(p6) fma.s1 f10 = f7, f6, f7 // q1 = q0*e0 + q0 +(p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 + ;; +#ifdef MODULO + sub in1 = r0, in1 // in1 = -b +#endif +(p6) fma.s1 f10 = f10, f7, f10 // q2 = q1*e1 + q1 +(p6) fma.s1 f6 = f11, f6, f11 // y1 = y0*e0 + y0 + ;; +(p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 +(p6) fnma.s1 f7 = f9, f10, f8 // r = -b*q2 + a + ;; +#ifdef MODULO + setf.sig f8 = in0 // f8 = a + setf.sig f9 = in1 // f9 = -b +#endif +(p6) fma.s1 f11 = f7, f6, f10 // q3 = r*y2 + q2 + ;; + FP_TO_INT(f11, f11) // q = trunc(q3) + ;; +#ifdef MODULO + xma.l f11 = f11, f9, f8 // r = q*(-b) + a + ;; +#endif + getf.sig r8 = f11 // transfer result to result register + br.ret.sptk.many rp +END(NAME) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/memcpy_mck.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/memcpy_mck.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,661 @@ +/* + * Itanium 2-optimized version of memcpy and copy_user function + * + * Inputs: + * in0: destination address + * in1: source address + * in2: number of bytes to copy + * Output: + * 0 if success, or number of byte NOT copied if error occurred. + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2002 Ken Chen <kenneth.w.chen@xxxxxxxxx> + */ +#include <linux/config.h> +#include <asm/asmmacro.h> +#include <asm/page.h> + +#define EK(y...) EX(y) + +/* McKinley specific optimization */ + +#define retval r8 +#define saved_pfs r31 +#define saved_lc r10 +#define saved_pr r11 +#define saved_in0 r14 +#define saved_in1 r15 +#define saved_in2 r16 + +#define src0 r2 +#define src1 r3 +#define dst0 r17 +#define dst1 r18 +#define cnt r9 + +/* r19-r30 are temp for each code section */ +#define PREFETCH_DIST 8 +#define src_pre_mem r19 +#define dst_pre_mem r20 +#define src_pre_l2 r21 +#define dst_pre_l2 r22 +#define t1 r23 +#define t2 r24 +#define t3 r25 +#define t4 r26 +#define t5 t1 // alias! +#define t6 t2 // alias! +#define t7 t3 // alias! +#define n8 r27 +#define t9 t5 // alias! +#define t10 t4 // alias! +#define t11 t7 // alias! +#define t12 t6 // alias! +#define t14 t10 // alias! +#define t13 r28 +#define t15 r29 +#define tmp r30 + +/* defines for long_copy block */ +#define A 0 +#define B (PREFETCH_DIST) +#define C (B + PREFETCH_DIST) +#define D (C + 1) +#define N (D + 1) +#define Nrot ((N + 7) & ~7) + +/* alias */ +#define in0 r32 +#define in1 r33 +#define in2 r34 + +GLOBAL_ENTRY(memcpy) + and r28=0x7,in0 + and r29=0x7,in1 + mov f6=f0 + br.cond.sptk .common_code + ;; +END(memcpy) +GLOBAL_ENTRY(__copy_user) + .prologue +// check dest alignment + and r28=0x7,in0 + and r29=0x7,in1 + mov f6=f1 + mov saved_in0=in0 // save dest pointer + mov saved_in1=in1 // save src pointer + mov saved_in2=in2 // save len + ;; +.common_code: + cmp.gt p15,p0=8,in2 // check for small size + cmp.ne p13,p0=0,r28 // check dest alignment + cmp.ne p14,p0=0,r29 // check src alignment + add src0=0,in1 + sub r30=8,r28 // for .align_dest + mov retval=r0 // initialize return value + ;; + add dst0=0,in0 + add dst1=1,in0 // dest odd index + cmp.le p6,p0 = 1,r30 // for .align_dest +(p15) br.cond.dpnt .memcpy_short +(p13) br.cond.dpnt .align_dest +(p14) br.cond.dpnt .unaligned_src + ;; + +// both dest and src are aligned on 8-byte boundary +.aligned_src: + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,Nrot-3,0,Nrot + .save pr, saved_pr + mov saved_pr=pr + + shr.u cnt=in2,7 // this much cache line + ;; + cmp.lt p6,p0=2*PREFETCH_DIST,cnt + cmp.lt p7,p8=1,cnt + .save ar.lc, saved_lc + mov saved_lc=ar.lc + .body + add cnt=-1,cnt + add src_pre_mem=0,in1 // prefetch src pointer + add dst_pre_mem=0,in0 // prefetch dest pointer + ;; +(p7) mov ar.lc=cnt // prefetch count +(p8) mov ar.lc=r0 +(p6) br.cond.dpnt .long_copy + ;; + +.prefetch: + lfetch.fault [src_pre_mem], 128 + lfetch.fault.excl [dst_pre_mem], 128 + br.cloop.dptk.few .prefetch + ;; + +.medium_copy: + and tmp=31,in2 // copy length after iteration + shr.u r29=in2,5 // number of 32-byte iteration + add dst1=8,dst0 // 2nd dest pointer + ;; + add cnt=-1,r29 // ctop iteration adjustment + cmp.eq p10,p0=r29,r0 // do we really need to loop? + add src1=8,src0 // 2nd src pointer + cmp.le p6,p0=8,tmp + ;; + cmp.le p7,p0=16,tmp + mov ar.lc=cnt // loop setup + cmp.eq p16,p17 = r0,r0 + mov ar.ec=2 +(p10) br.dpnt.few .aligned_src_tail + ;; + TEXT_ALIGN(32) +1: +EX(.ex_handler, (p16) ld8 r34=[src0],16) +EK(.ex_handler, (p16) ld8 r38=[src1],16) +EX(.ex_handler, (p17) st8 [dst0]=r33,16) +EK(.ex_handler, (p17) st8 [dst1]=r37,16) + ;; +EX(.ex_handler, (p16) ld8 r32=[src0],16) +EK(.ex_handler, (p16) ld8 r36=[src1],16) +EX(.ex_handler, (p16) st8 [dst0]=r34,16) +EK(.ex_handler, (p16) st8 [dst1]=r38,16) + br.ctop.dptk.few 1b + ;; + +.aligned_src_tail: +EX(.ex_handler, (p6) ld8 t1=[src0]) + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs +EX(.ex_hndlr_s, (p7) ld8 t2=[src1],8) + cmp.le p8,p0=24,tmp + and r21=-8,tmp + ;; +EX(.ex_hndlr_s, (p8) ld8 t3=[src1]) +EX(.ex_handler, (p6) st8 [dst0]=t1) // store byte 1 + and in2=7,tmp // remaining length +EX(.ex_hndlr_d, (p7) st8 [dst1]=t2,8) // store byte 2 + add src0=src0,r21 // setting up src pointer + add dst0=dst0,r21 // setting up dest pointer + ;; +EX(.ex_handler, (p8) st8 [dst1]=t3) // store byte 3 + mov pr=saved_pr,-1 + br.dptk.many .memcpy_short + ;; + +/* code taken from copy_page_mck */ +.long_copy: + .rotr v[2*PREFETCH_DIST] + .rotp p[N] + + mov src_pre_mem = src0 + mov pr.rot = 0x10000 + mov ar.ec = 1 // special unrolled loop + + mov dst_pre_mem = dst0 + + add src_pre_l2 = 8*8, src0 + add dst_pre_l2 = 8*8, dst0 + ;; + add src0 = 8, src_pre_mem // first t1 src + mov ar.lc = 2*PREFETCH_DIST - 1 + shr.u cnt=in2,7 // number of lines + add src1 = 3*8, src_pre_mem // first t3 src + add dst0 = 8, dst_pre_mem // first t1 dst + add dst1 = 3*8, dst_pre_mem // first t3 dst + ;; + and tmp=127,in2 // remaining bytes after this block + add cnt = -(2*PREFETCH_DIST) - 1, cnt + // same as .line_copy loop, but with all predicated-off instructions removed: +.prefetch_loop: +EX(.ex_hndlr_lcpy_1, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 +EK(.ex_hndlr_lcpy_1, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 + br.ctop.sptk .prefetch_loop + ;; + cmp.eq p16, p0 = r0, r0 // reset p16 to 1 + mov ar.lc = cnt + mov ar.ec = N // # of stages in pipeline + ;; +.line_copy: +EX(.ex_handler, (p[D]) ld8 t2 = [src0], 3*8) // M0 +EK(.ex_handler, (p[D]) ld8 t4 = [src1], 3*8) // M1 +EX(.ex_handler_lcpy, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 prefetch dst from memory +EK(.ex_handler_lcpy, (p[D]) st8 [dst_pre_l2] = n8, 128) // M3 prefetch dst from L2 + ;; +EX(.ex_handler_lcpy, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 prefetch src from memory +EK(.ex_handler_lcpy, (p[C]) ld8 n8 = [src_pre_l2], 128) // M1 prefetch src from L2 +EX(.ex_handler, (p[D]) st8 [dst0] = t1, 8) // M2 +EK(.ex_handler, (p[D]) st8 [dst1] = t3, 8) // M3 + ;; +EX(.ex_handler, (p[D]) ld8 t5 = [src0], 8) +EK(.ex_handler, (p[D]) ld8 t7 = [src1], 3*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t2, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t4, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t6 = [src0], 3*8) +EK(.ex_handler, (p[D]) ld8 t10 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t5, 8) +EK(.ex_handler, (p[D]) st8 [dst1] = t7, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t9 = [src0], 3*8) +EK(.ex_handler, (p[D]) ld8 t11 = [src1], 3*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t6, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t10, 8) + ;; +EX(.ex_handler, (p[D]) ld8 t12 = [src0], 8) +EK(.ex_handler, (p[D]) ld8 t14 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t9, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t11, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t13 = [src0], 4*8) +EK(.ex_handler, (p[D]) ld8 t15 = [src1], 4*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t12, 8) +EK(.ex_handler, (p[D]) st8 [dst1] = t14, 8) + ;; +EX(.ex_handler, (p[C]) ld8 t1 = [src0], 8) +EK(.ex_handler, (p[C]) ld8 t3 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t13, 4*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t15, 4*8) + br.ctop.sptk .line_copy + ;; + + add dst0=-8,dst0 + add src0=-8,src0 + mov in2=tmp + .restore sp + br.sptk.many .medium_copy + ;; + +#define BLOCK_SIZE 128*32 +#define blocksize r23 +#define curlen r24 + +// dest is on 8-byte boundary, src is not. We need to do +// ld8-ld8, shrp, then st8. Max 8 byte copy per cycle. +.unaligned_src: + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,5,0,8 + .save ar.lc, saved_lc + mov saved_lc=ar.lc + .save pr, saved_pr + mov saved_pr=pr + .body +.4k_block: + mov saved_in0=dst0 // need to save all input arguments + mov saved_in2=in2 + mov blocksize=BLOCK_SIZE + ;; + cmp.lt p6,p7=blocksize,in2 + mov saved_in1=src0 + ;; +(p6) mov in2=blocksize + ;; + shr.u r21=in2,7 // this much cache line + shr.u r22=in2,4 // number of 16-byte iteration + and curlen=15,in2 // copy length after iteration + and r30=7,src0 // source alignment + ;; + cmp.lt p7,p8=1,r21 + add cnt=-1,r21 + ;; + + add src_pre_mem=0,src0 // prefetch src pointer + add dst_pre_mem=0,dst0 // prefetch dest pointer + and src0=-8,src0 // 1st src pointer +(p7) mov ar.lc = cnt +(p8) mov ar.lc = r0 + ;; + TEXT_ALIGN(32) +1: lfetch.fault [src_pre_mem], 128 + lfetch.fault.excl [dst_pre_mem], 128 + br.cloop.dptk.few 1b + ;; + + shladd dst1=r22,3,dst0 // 2nd dest pointer + shladd src1=r22,3,src0 // 2nd src pointer + cmp.eq p8,p9=r22,r0 // do we really need to loop? + cmp.le p6,p7=8,curlen; // have at least 8 byte remaining? + add cnt=-1,r22 // ctop iteration adjustment + ;; +EX(.ex_handler, (p9) ld8 r33=[src0],8) // loop primer +EK(.ex_handler, (p9) ld8 r37=[src1],8) +(p8) br.dpnt.few .noloop + ;; + +// The jump address is calculated based on src alignment. The COPYU +// macro below need to confine its size to power of two, so an entry +// can be caulated using shl instead of an expensive multiply. The +// size is then hard coded by the following #define to match the +// actual size. This make it somewhat tedious when COPYU macro gets +// changed and this need to be adjusted to match. +#define LOOP_SIZE 6 +1: + mov r29=ip // jmp_table thread + mov ar.lc=cnt + ;; + add r29=.jump_table - 1b - (.jmp1-.jump_table), r29 + shl r28=r30, LOOP_SIZE // jmp_table thread + mov ar.ec=2 // loop setup + ;; + add r29=r29,r28 // jmp_table thread + cmp.eq p16,p17=r0,r0 + ;; + mov b6=r29 // jmp_table thread + ;; + br.cond.sptk.few b6 + +// for 8-15 byte case +// We will skip the loop, but need to replicate the side effect +// that the loop produces. +.noloop: +EX(.ex_handler, (p6) ld8 r37=[src1],8) + add src0=8,src0 +(p6) shl r25=r30,3 + ;; +EX(.ex_handler, (p6) ld8 r27=[src1]) +(p6) shr.u r28=r37,r25 +(p6) sub r26=64,r25 + ;; +(p6) shl r27=r27,r26 + ;; +(p6) or r21=r28,r27 + +.unaligned_src_tail: +/* check if we have more than blocksize to copy, if so go back */ + cmp.gt p8,p0=saved_in2,blocksize + ;; +(p8) add dst0=saved_in0,blocksize +(p8) add src0=saved_in1,blocksize +(p8) sub in2=saved_in2,blocksize +(p8) br.dpnt .4k_block + ;; + +/* we have up to 15 byte to copy in the tail. + * part of work is already done in the jump table code + * we are at the following state. + * src side: + * + * xxxxxx xx <----- r21 has xxxxxxxx already + * -------- -------- -------- + * 0 8 16 + * ^ + * | + * src1 + * + * dst + * -------- -------- -------- + * ^ + * | + * dst1 + */ +EX(.ex_handler, (p6) st8 [dst1]=r21,8) // more than 8 byte to copy +(p6) add curlen=-8,curlen // update length + mov ar.pfs=saved_pfs + ;; + mov ar.lc=saved_lc + mov pr=saved_pr,-1 + mov in2=curlen // remaining length + mov dst0=dst1 // dest pointer + add src0=src1,r30 // forward by src alignment + ;; + +// 7 byte or smaller. +.memcpy_short: + cmp.le p8,p9 = 1,in2 + cmp.le p10,p11 = 2,in2 + cmp.le p12,p13 = 3,in2 + cmp.le p14,p15 = 4,in2 + add src1=1,src0 // second src pointer + add dst1=1,dst0 // second dest pointer + ;; + +EX(.ex_handler_short, (p8) ld1 t1=[src0],2) +EK(.ex_handler_short, (p10) ld1 t2=[src1],2) +(p9) br.ret.dpnt rp // 0 byte copy + ;; + +EX(.ex_handler_short, (p8) st1 [dst0]=t1,2) +EK(.ex_handler_short, (p10) st1 [dst1]=t2,2) +(p11) br.ret.dpnt rp // 1 byte copy + +EX(.ex_handler_short, (p12) ld1 t3=[src0],2) +EK(.ex_handler_short, (p14) ld1 t4=[src1],2) +(p13) br.ret.dpnt rp // 2 byte copy + ;; + + cmp.le p6,p7 = 5,in2 + cmp.le p8,p9 = 6,in2 + cmp.le p10,p11 = 7,in2 + +EX(.ex_handler_short, (p12) st1 [dst0]=t3,2) +EK(.ex_handler_short, (p14) st1 [dst1]=t4,2) +(p15) br.ret.dpnt rp // 3 byte copy + ;; + +EX(.ex_handler_short, (p6) ld1 t5=[src0],2) +EK(.ex_handler_short, (p8) ld1 t6=[src1],2) +(p7) br.ret.dpnt rp // 4 byte copy + ;; + +EX(.ex_handler_short, (p6) st1 [dst0]=t5,2) +EK(.ex_handler_short, (p8) st1 [dst1]=t6,2) +(p9) br.ret.dptk rp // 5 byte copy + +EX(.ex_handler_short, (p10) ld1 t7=[src0],2) +(p11) br.ret.dptk rp // 6 byte copy + ;; + +EX(.ex_handler_short, (p10) st1 [dst0]=t7,2) + br.ret.dptk rp // done all cases + + +/* Align dest to nearest 8-byte boundary. We know we have at + * least 7 bytes to copy, enough to crawl to 8-byte boundary. + * Actual number of byte to crawl depend on the dest alignment. + * 7 byte or less is taken care at .memcpy_short + + * src0 - source even index + * src1 - source odd index + * dst0 - dest even index + * dst1 - dest odd index + * r30 - distance to 8-byte boundary + */ + +.align_dest: + add src1=1,in1 // source odd index + cmp.le p7,p0 = 2,r30 // for .align_dest + cmp.le p8,p0 = 3,r30 // for .align_dest +EX(.ex_handler_short, (p6) ld1 t1=[src0],2) + cmp.le p9,p0 = 4,r30 // for .align_dest + cmp.le p10,p0 = 5,r30 + ;; +EX(.ex_handler_short, (p7) ld1 t2=[src1],2) +EK(.ex_handler_short, (p8) ld1 t3=[src0],2) + cmp.le p11,p0 = 6,r30 +EX(.ex_handler_short, (p6) st1 [dst0] = t1,2) + cmp.le p12,p0 = 7,r30 + ;; +EX(.ex_handler_short, (p9) ld1 t4=[src1],2) +EK(.ex_handler_short, (p10) ld1 t5=[src0],2) +EX(.ex_handler_short, (p7) st1 [dst1] = t2,2) +EK(.ex_handler_short, (p8) st1 [dst0] = t3,2) + ;; +EX(.ex_handler_short, (p11) ld1 t6=[src1],2) +EK(.ex_handler_short, (p12) ld1 t7=[src0],2) + cmp.eq p6,p7=r28,r29 +EX(.ex_handler_short, (p9) st1 [dst1] = t4,2) +EK(.ex_handler_short, (p10) st1 [dst0] = t5,2) + sub in2=in2,r30 + ;; +EX(.ex_handler_short, (p11) st1 [dst1] = t6,2) +EK(.ex_handler_short, (p12) st1 [dst0] = t7) + add dst0=in0,r30 // setup arguments + add src0=in1,r30 +(p6) br.cond.dptk .aligned_src +(p7) br.cond.dpnt .unaligned_src + ;; + +/* main loop body in jump table format */ +#define COPYU(shift) \ +1: \ +EX(.ex_handler, (p16) ld8 r32=[src0],8); /* 1 */ \ +EK(.ex_handler, (p16) ld8 r36=[src1],8); \ + (p17) shrp r35=r33,r34,shift;; /* 1 */ \ +EX(.ex_handler, (p6) ld8 r22=[src1]); /* common, prime for tail section */ \ + nop.m 0; \ + (p16) shrp r38=r36,r37,shift; \ +EX(.ex_handler, (p17) st8 [dst0]=r35,8); /* 1 */ \ +EK(.ex_handler, (p17) st8 [dst1]=r39,8); \ + br.ctop.dptk.few 1b;; \ + (p7) add src1=-8,src1; /* back out for <8 byte case */ \ + shrp r21=r22,r38,shift; /* speculative work */ \ + br.sptk.few .unaligned_src_tail /* branch out of jump table */ \ + ;; + TEXT_ALIGN(32) +.jump_table: + COPYU(8) // unaligned cases +.jmp1: + COPYU(16) + COPYU(24) + COPYU(32) + COPYU(40) + COPYU(48) + COPYU(56) + +#undef A +#undef B +#undef C +#undef D + +/* + * Due to lack of local tag support in gcc 2.x assembler, it is not clear which + * instruction failed in the bundle. The exception algorithm is that we + * first figure out the faulting address, then detect if there is any + * progress made on the copy, if so, redo the copy from last known copied + * location up to the faulting address (exclusive). In the copy_from_user + * case, remaining byte in kernel buffer will be zeroed. + * + * Take copy_from_user as an example, in the code there are multiple loads + * in a bundle and those multiple loads could span over two pages, the + * faulting address is calculated as page_round_down(max(src0, src1)). + * This is based on knowledge that if we can access one byte in a page, we + * can access any byte in that page. + * + * predicate used in the exception handler: + * p6-p7: direction + * p10-p11: src faulting addr calculation + * p12-p13: dst faulting addr calculation + */ + +#define A r19 +#define B r20 +#define C r21 +#define D r22 +#define F r28 + +#define memset_arg0 r32 +#define memset_arg2 r33 + +#define saved_retval loc0 +#define saved_rtlink loc1 +#define saved_pfs_stack loc2 + +.ex_hndlr_s: + add src0=8,src0 + br.sptk .ex_handler + ;; +.ex_hndlr_d: + add dst0=8,dst0 + br.sptk .ex_handler + ;; +.ex_hndlr_lcpy_1: + mov src1=src_pre_mem + mov dst1=dst_pre_mem + cmp.gtu p10,p11=src_pre_mem,saved_in1 + cmp.gtu p12,p13=dst_pre_mem,saved_in0 + ;; +(p10) add src0=8,saved_in1 +(p11) mov src0=saved_in1 +(p12) add dst0=8,saved_in0 +(p13) mov dst0=saved_in0 + br.sptk .ex_handler +.ex_handler_lcpy: + // in line_copy block, the preload addresses should always ahead + // of the other two src/dst pointers. Furthermore, src1/dst1 should + // always ahead of src0/dst0. + mov src1=src_pre_mem + mov dst1=dst_pre_mem +.ex_handler: + mov pr=saved_pr,-1 // first restore pr, lc, and pfs + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + ;; +.ex_handler_short: // fault occurred in these sections didn't change pr, lc, pfs + cmp.ltu p6,p7=saved_in0, saved_in1 // get the copy direction + cmp.ltu p10,p11=src0,src1 + cmp.ltu p12,p13=dst0,dst1 + fcmp.eq p8,p0=f6,f0 // is it memcpy? + mov tmp = dst0 + ;; +(p11) mov src1 = src0 // pick the larger of the two +(p13) mov dst0 = dst1 // make dst0 the smaller one +(p13) mov dst1 = tmp // and dst1 the larger one + ;; +(p6) dep F = r0,dst1,0,PAGE_SHIFT // usr dst round down to page boundary +(p7) dep F = r0,src1,0,PAGE_SHIFT // usr src round down to page boundary + ;; +(p6) cmp.le p14,p0=dst0,saved_in0 // no progress has been made on store +(p7) cmp.le p14,p0=src0,saved_in1 // no progress has been made on load + mov retval=saved_in2 +(p8) ld1 tmp=[src1] // force an oops for memcpy call +(p8) st1 [dst1]=r0 // force an oops for memcpy call +(p14) br.ret.sptk.many rp + +/* + * The remaining byte to copy is calculated as: + * + * A = (faulting_addr - orig_src) -> len to faulting ld address + * or + * (faulting_addr - orig_dst) -> len to faulting st address + * B = (cur_dst - orig_dst) -> len copied so far + * C = A - B -> len need to be copied + * D = orig_len - A -> len need to be zeroed + */ +(p6) sub A = F, saved_in0 +(p7) sub A = F, saved_in1 + clrrrb + ;; + alloc saved_pfs_stack=ar.pfs,3,3,3,0 + sub B = dst0, saved_in0 // how many byte copied so far + ;; + sub C = A, B + sub D = saved_in2, A + ;; + cmp.gt p8,p0=C,r0 // more than 1 byte? + add memset_arg0=saved_in0, A +(p6) mov memset_arg2=0 // copy_to_user should not call memset +(p7) mov memset_arg2=D // copy_from_user need to have kbuf zeroed + mov r8=0 + mov saved_retval = D + mov saved_rtlink = b0 + + add out0=saved_in0, B + add out1=saved_in1, B + mov out2=C +(p8) br.call.sptk.few b0=__copy_user // recursive call + ;; + + add saved_retval=saved_retval,r8 // above might return non-zero value + cmp.gt p8,p0=memset_arg2,r0 // more than 1 byte? + mov out0=memset_arg0 // *s + mov out1=r0 // c + mov out2=memset_arg2 // n +(p8) br.call.sptk.few b0=memset + ;; + + mov retval=saved_retval + mov ar.pfs=saved_pfs_stack + mov b0=saved_rtlink + br.ret.sptk.many rp + +/* end of McKinley specific optimization */ +END(__copy_user) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/memset.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/memset.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,362 @@ +/* Optimized version of the standard memset() function. + + Copyright (c) 2002 Hewlett-Packard Co/CERN + Sverre Jarp <Sverre.Jarp@xxxxxxx> + + Return: dest + + Inputs: + in0: dest + in1: value + in2: count + + The algorithm is fairly straightforward: set byte by byte until we + we get to a 16B-aligned address, then loop on 128 B chunks using an + early store as prefetching, then loop on 32B chucks, then clear remaining + words, finally clear remaining bytes. + Since a stf.spill f0 can store 16B in one go, we use this instruction + to get peak speed when value = 0. */ + +#include <asm/asmmacro.h> +#undef ret + +#define dest in0 +#define value in1 +#define cnt in2 + +#define tmp r31 +#define save_lc r30 +#define ptr0 r29 +#define ptr1 r28 +#define ptr2 r27 +#define ptr3 r26 +#define ptr9 r24 +#define loopcnt r23 +#define linecnt r22 +#define bytecnt r21 + +#define fvalue f6 + +// This routine uses only scratch predicate registers (p6 - p15) +#define p_scr p6 // default register for same-cycle branches +#define p_nz p7 +#define p_zr p8 +#define p_unalgn p9 +#define p_y p11 +#define p_n p12 +#define p_yy p13 +#define p_nn p14 + +#define MIN1 15 +#define MIN1P1HALF 8 +#define LINE_SIZE 128 +#define LSIZE_SH 7 // shift amount +#define PREF_AHEAD 8 + +GLOBAL_ENTRY(memset) +{ .mmi + .prologue + alloc tmp = ar.pfs, 3, 0, 0, 0 + lfetch.nt1 [dest] // + .save ar.lc, save_lc + mov.i save_lc = ar.lc + .body +} { .mmi + mov ret0 = dest // return value + cmp.ne p_nz, p_zr = value, r0 // use stf.spill if value is zero + cmp.eq p_scr, p0 = cnt, r0 +;; } +{ .mmi + and ptr2 = -(MIN1+1), dest // aligned address + and tmp = MIN1, dest // prepare to check for correct alignment + tbit.nz p_y, p_n = dest, 0 // Do we have an odd address? (M_B_U) +} { .mib + mov ptr1 = dest + mux1 value = value, @brcst // create 8 identical bytes in word +(p_scr) br.ret.dpnt.many rp // return immediately if count = 0 +;; } +{ .mib + cmp.ne p_unalgn, p0 = tmp, r0 // +} { .mib + sub bytecnt = (MIN1+1), tmp // NB: # of bytes to move is 1 higher than loopcnt + cmp.gt p_scr, p0 = 16, cnt // is it a minimalistic task? +(p_scr) br.cond.dptk.many .move_bytes_unaligned // go move just a few (M_B_U) +;; } +{ .mmi +(p_unalgn) add ptr1 = (MIN1+1), ptr2 // after alignment +(p_unalgn) add ptr2 = MIN1P1HALF, ptr2 // after alignment +(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 3 // should we do a st8 ? +;; } +{ .mib +(p_y) add cnt = -8, cnt // +(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 2 // should we do a st4 ? +} { .mib +(p_y) st8 [ptr2] = value,-4 // +(p_n) add ptr2 = 4, ptr2 // +;; } +{ .mib +(p_yy) add cnt = -4, cnt // +(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 1 // should we do a st2 ? +} { .mib +(p_yy) st4 [ptr2] = value,-2 // +(p_nn) add ptr2 = 2, ptr2 // +;; } +{ .mmi + mov tmp = LINE_SIZE+1 // for compare +(p_y) add cnt = -2, cnt // +(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 0 // should we do a st1 ? +} { .mmi + setf.sig fvalue=value // transfer value to FLP side +(p_y) st2 [ptr2] = value,-1 // +(p_n) add ptr2 = 1, ptr2 // +;; } + +{ .mmi +(p_yy) st1 [ptr2] = value // + cmp.gt p_scr, p0 = tmp, cnt // is it a minimalistic task? +} { .mbb +(p_yy) add cnt = -1, cnt // +(p_scr) br.cond.dpnt.many .fraction_of_line // go move just a few +;; } + +{ .mib + nop.m 0 + shr.u linecnt = cnt, LSIZE_SH +(p_zr) br.cond.dptk.many .l1b // Jump to use stf.spill +;; } + + TEXT_ALIGN(32) // --------------------- // L1A: store ahead into cache lines; fill later +{ .mmi + and tmp = -(LINE_SIZE), cnt // compute end of range + mov ptr9 = ptr1 // used for prefetching + and cnt = (LINE_SIZE-1), cnt // remainder +} { .mmi + mov loopcnt = PREF_AHEAD-1 // default prefetch loop + cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value +;; } +{ .mmi +(p_scr) add loopcnt = -1, linecnt // + add ptr2 = 8, ptr1 // start of stores (beyond prefetch stores) + add ptr1 = tmp, ptr1 // first address beyond total range +;; } +{ .mmi + add tmp = -1, linecnt // next loop count + mov.i ar.lc = loopcnt // +;; } +.pref_l1a: +{ .mib + stf8 [ptr9] = fvalue, 128 // Do stores one cache line apart + nop.i 0 + br.cloop.dptk.few .pref_l1a +;; } +{ .mmi + add ptr0 = 16, ptr2 // Two stores in parallel + mov.i ar.lc = tmp // +;; } +.l1ax: + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 32 + cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? + ;; } +{ .mmb + stf8 [ptr2] = fvalue, 24 +(p_scr) stf8 [ptr9] = fvalue, 128 + br.cloop.dptk.few .l1ax +;; } +{ .mbb + cmp.le p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .fraction_of_line // Branch no. 2 + br.cond.dpnt.many .move_bytes_from_alignment // Branch no. 3 +;; } + + TEXT_ALIGN(32) +.l1b: // ------------------------------------ // L1B: store ahead into cache lines; fill later +{ .mmi + and tmp = -(LINE_SIZE), cnt // compute end of range + mov ptr9 = ptr1 // used for prefetching + and cnt = (LINE_SIZE-1), cnt // remainder +} { .mmi + mov loopcnt = PREF_AHEAD-1 // default prefetch loop + cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value +;; } +{ .mmi +(p_scr) add loopcnt = -1, linecnt + add ptr2 = 16, ptr1 // start of stores (beyond prefetch stores) + add ptr1 = tmp, ptr1 // first address beyond total range +;; } +{ .mmi + add tmp = -1, linecnt // next loop count + mov.i ar.lc = loopcnt +;; } +.pref_l1b: +{ .mib + stf.spill [ptr9] = f0, 128 // Do stores one cache line apart + nop.i 0 + br.cloop.dptk.few .pref_l1b +;; } +{ .mmi + add ptr0 = 16, ptr2 // Two stores in parallel + mov.i ar.lc = tmp +;; } +.l1bx: + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 32 + ;; } + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 32 + ;; } + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 64 + cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? + ;; } +{ .mmb + stf.spill [ptr2] = f0, 32 +(p_scr) stf.spill [ptr9] = f0, 128 + br.cloop.dptk.few .l1bx +;; } +{ .mib + cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // +;; } + +.fraction_of_line: +{ .mib + add ptr2 = 16, ptr1 + shr.u loopcnt = cnt, 5 // loopcnt = cnt / 32 +;; } +{ .mib + cmp.eq p_scr, p0 = loopcnt, r0 + add loopcnt = -1, loopcnt +(p_scr) br.cond.dpnt.many .store_words +;; } +{ .mib + and cnt = 0x1f, cnt // compute the remaining cnt + mov.i ar.lc = loopcnt +;; } + TEXT_ALIGN(32) +.l2: // ------------------------------------ // L2A: store 32B in 2 cycles +{ .mmb + stf8 [ptr1] = fvalue, 8 + stf8 [ptr2] = fvalue, 8 +;; } { .mmb + stf8 [ptr1] = fvalue, 24 + stf8 [ptr2] = fvalue, 24 + br.cloop.dptk.many .l2 +;; } +.store_words: +{ .mib + cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // Branch +;; } + +{ .mmi + stf8 [ptr1] = fvalue, 8 // store + cmp.le p_y, p_n = 16, cnt + add cnt = -8, cnt // subtract +;; } +{ .mmi +(p_y) stf8 [ptr1] = fvalue, 8 // store +(p_y) cmp.le.unc p_yy, p_nn = 16, cnt +(p_y) add cnt = -8, cnt // subtract +;; } +{ .mmi // store +(p_yy) stf8 [ptr1] = fvalue, 8 +(p_yy) add cnt = -8, cnt // subtract +;; } + +.move_bytes_from_alignment: +{ .mib + cmp.eq p_scr, p0 = cnt, r0 + tbit.nz.unc p_y, p0 = cnt, 2 // should we terminate with a st4 ? +(p_scr) br.cond.dpnt.few .restore_and_exit +;; } +{ .mib +(p_y) st4 [ptr1] = value,4 + tbit.nz.unc p_yy, p0 = cnt, 1 // should we terminate with a st2 ? +;; } +{ .mib +(p_yy) st2 [ptr1] = value,2 + tbit.nz.unc p_y, p0 = cnt, 0 // should we terminate with a st1 ? +;; } + +{ .mib +(p_y) st1 [ptr1] = value +;; } +.restore_and_exit: +{ .mib + nop.m 0 + mov.i ar.lc = save_lc + br.ret.sptk.many rp +;; } + +.move_bytes_unaligned: +{ .mmi + .pred.rel "mutex",p_y, p_n + .pred.rel "mutex",p_yy, p_nn +(p_n) cmp.le p_yy, p_nn = 4, cnt +(p_y) cmp.le p_yy, p_nn = 5, cnt +(p_n) add ptr2 = 2, ptr1 +} { .mmi +(p_y) add ptr2 = 3, ptr1 +(p_y) st1 [ptr1] = value, 1 // fill 1 (odd-aligned) byte [15, 14 (or less) left] +(p_y) add cnt = -1, cnt +;; } +{ .mmi +(p_yy) cmp.le.unc p_y, p0 = 8, cnt + add ptr3 = ptr1, cnt // prepare last store + mov.i ar.lc = save_lc +} { .mmi +(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [11, 10 (o less) left] +(p_yy) add cnt = -4, cnt +;; } +{ .mmi +(p_y) cmp.le.unc p_yy, p0 = 8, cnt + add ptr3 = -1, ptr3 // last store + tbit.nz p_scr, p0 = cnt, 1 // will there be a st2 at the end ? +} { .mmi +(p_y) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_y) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [7, 6 (or less) left] +(p_y) add cnt = -4, cnt +;; } +{ .mmi +(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [3, 2 (or less) left] + tbit.nz p_y, p0 = cnt, 0 // will there be a st1 at the end ? +} { .mmi +(p_yy) add cnt = -4, cnt +;; } +{ .mmb +(p_scr) st2 [ptr1] = value // fill 2 (aligned) bytes +(p_y) st1 [ptr3] = value // fill last byte (using ptr3) + br.ret.sptk.many rp +} +END(memset) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/strlen.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/linux/strlen.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,192 @@ +/* + * + * Optimized version of the standard strlen() function + * + * + * Inputs: + * in0 address of string + * + * Outputs: + * ret0 the number of characters in the string (0 if empty string) + * does not count the \0 + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * Stephane Eranian <eranian@xxxxxxxxxx> + * + * 09/24/99 S.Eranian add speculation recovery code + */ + +#include <asm/asmmacro.h> + +// +// +// This is an enhanced version of the basic strlen. it includes a combination +// of compute zero index (czx), parallel comparisons, speculative loads and +// loop unroll using rotating registers. +// +// General Ideas about the algorithm: +// The goal is to look at the string in chunks of 8 bytes. +// so we need to do a few extra checks at the beginning because the +// string may not be 8-byte aligned. In this case we load the 8byte +// quantity which includes the start of the string and mask the unused +// bytes with 0xff to avoid confusing czx. +// We use speculative loads and software pipelining to hide memory +// latency and do read ahead safely. This way we defer any exception. +// +// Because we don't want the kernel to be relying on particular +// settings of the DCR register, we provide recovery code in case +// speculation fails. The recovery code is going to "redo" the work using +// only normal loads. If we still get a fault then we generate a +// kernel panic. Otherwise we return the strlen as usual. +// +// The fact that speculation may fail can be caused, for instance, by +// the DCR.dm bit being set. In this case TLB misses are deferred, i.e., +// a NaT bit will be set if the translation is not present. The normal +// load, on the other hand, will cause the translation to be inserted +// if the mapping exists. +// +// It should be noted that we execute recovery code only when we need +// to use the data that has been speculatively loaded: we don't execute +// recovery code on pure read ahead data. +// +// Remarks: +// - the cmp r0,r0 is used as a fast way to initialize a predicate +// register to 1. This is required to make sure that we get the parallel +// compare correct. +// +// - we don't use the epilogue counter to exit the loop but we need to set +// it to zero beforehand. +// +// - after the loop we must test for Nat values because neither the +// czx nor cmp instruction raise a NaT consumption fault. We must be +// careful not to look too far for a Nat for which we don't care. +// For instance we don't need to look at a NaT in val2 if the zero byte +// was in val1. +// +// - Clearly performance tuning is required. +// +// +// +#define saved_pfs r11 +#define tmp r10 +#define base r16 +#define orig r17 +#define saved_pr r18 +#define src r19 +#define mask r20 +#define val r21 +#define val1 r22 +#define val2 r23 + +GLOBAL_ENTRY(strlen) + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 + + .rotr v[2], w[2] // declares our 4 aliases + + extr.u tmp=in0,0,3 // tmp=least significant 3 bits + mov orig=in0 // keep trackof initial byte address + dep src=0,in0,0,3 // src=8byte-aligned in0 address + .save pr, saved_pr + mov saved_pr=pr // preserve predicates (rotation) + ;; + + .body + + ld8 v[1]=[src],8 // must not speculate: can fail here + shl tmp=tmp,3 // multiply by 8bits/byte + mov mask=-1 // our mask + ;; + ld8.s w[1]=[src],8 // speculatively load next + cmp.eq p6,p0=r0,r0 // sets p6 to true for cmp.and + sub tmp=64,tmp // how many bits to shift our mask on the right + ;; + shr.u mask=mask,tmp // zero enough bits to hold v[1] valuable part + mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) + ;; + add base=-16,src // keep track of aligned base + or v[1]=v[1],mask // now we have a safe initial byte pattern + ;; +1: + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right + czx1.r val2=w[1] // search 0 byte from right following 8bytes + ;; + ld8.s w[0]=[src],8 // speculatively load next to next + cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 + cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 +(p6) br.wtop.dptk 1b // loop until p6 == 0 + ;; + // + // We must return try the recovery code iff + // val1_is_nat || (val1==8 && val2_is_nat) + // + // XXX Fixme + // - there must be a better way of doing the test + // + cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) + tnat.nz p6,p7=val1 // test NaT on val1 +(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT + ;; + // + // if we come here p7 is true, i.e., initialized for // cmp + // + cmp.eq.and p7,p0=8,val1// val1==8? + tnat.nz.and p7,p0=val2 // test NaT if val2 +(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT + ;; +(p8) mov val1=val2 // the other test got us out of the loop +(p8) adds src=-16,src // correct position when 3 ahead +(p9) adds src=-24,src // correct position when 4 ahead + ;; + sub ret0=src,orig // distance from base + sub tmp=8,val1 // which byte in word + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // adjust + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.many rp // end of normal execution + + // + // Outlined recovery code when speculation failed + // + // This time we don't use speculation and rely on the normal exception + // mechanism. that's why the loop is not as good as the previous one + // because read ahead is not possible + // + // IMPORTANT: + // Please note that in the case of strlen() as opposed to strlen_user() + // we don't use the exception mechanism, as this function is not + // supposed to fail. If that happens it means we have a bug and the + // code will cause of kernel fault. + // + // XXX Fixme + // - today we restart from the beginning of the string instead + // of trying to continue where we left off. + // +.recover: + ld8 val=[base],8 // will fail if unrecoverable fault + ;; + or val=val,mask // remask first bytes + cmp.eq p0,p6=r0,r0 // nullify first ld8 in loop + ;; + // + // ar.ec is still zero here + // +2: +(p6) ld8 val=[base],8 // will fail if unrecoverable fault + ;; + czx1.r val1=val // search 0 byte from right + ;; + cmp.eq p6,p0=8,val1 // val1==8 ? +(p6) br.wtop.dptk 2b // loop until p6 == 0 + ;; // (avoid WAW on p63) + sub ret0=base,orig // distance from base + sub tmp=8,val1 + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // length=now - back -1 + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.many rp // end of successful recovery code +END(strlen) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/mm.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/mm.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,152 @@ +/****************************************************************************** + * 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@xxxxxxxxx) + * + * 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 + */ +#ifdef CONFIG_VTI +int 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 = redistribute_rid(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; + } + thash_purge_and_insert(hcb, &entry); + }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; +} +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/mmio.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/mmio.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,515 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * mmio.c: MMIO emulation components. + * Copyright (c) 2004, Intel Corporation. + * + * 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. + * + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + * Kun Tian (Kevin Tian) (Kevin.tian@xxxxxxxxx) + */ + +#include <linux/sched.h> +#include <asm/tlb.h> +#include <asm/vmx_mm_def.h> +#include <asm/gcc_intrin.h> +#include <linux/interrupt.h> +#include <asm/vmx_vcpu.h> +#include <asm/privop.h> +#include <asm/types.h> +#include <public/io/ioreq.h> +#include <asm/mm.h> +#include <asm/vmx.h> + +/* +struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) +{ + int i; + for (i=0; mio_base[i].iot != NOT_IO; i++ ) { + if ( gpa >= mio_base[i].start && gpa <= mio_base[i].end ) + return &mio_base[i]; + } + return NULL; +} +*/ + +#define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) +#define PIB_OFST_INTA 0x1E0000 +#define PIB_OFST_XTP 0x1E0008 + +static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) +{ + switch (pib_off) { + case PIB_OFST_INTA: + panic("Undefined write on PIB INTA\n"); + break; + case PIB_OFST_XTP: + if ( s == 1 && ma == 4 /* UC */) { + vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src; + } + else { + panic("Undefined write on PIB XTP\n"); + } + break; + default: + if ( PIB_LOW_HALF(pib_off) ) { // lower half + if ( s != 8 || ma != 0x4 /* UC */ ) { + panic("Undefined IPI-LHF write with s %d, ma %d!\n", s, ma); + } + else { + write_ipi(vcpu, pib_off, *(uint64_t *)src); + // TODO for SM-VP + } + } + else { // upper half + printf("IPI-UHF write %lx\n",pib_off); + panic("Not support yet for SM-VP\n"); + } + break; + } +} + +static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) +{ + switch (pib_off) { + case PIB_OFST_INTA: + // todo --- emit on processor system bus. + if ( s == 1 && ma == 4) { // 1 byte load + // TODO: INTA read from IOSAPIC + } + else { + panic("Undefined read on PIB INTA\n"); + } + break; + case PIB_OFST_XTP: + if ( s == 1 && ma == 4) { + *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp; + } + else { + panic("Undefined read on PIB XTP\n"); + } + break; + default: + if ( PIB_LOW_HALF(pib_off) ) { // lower half + if ( s != 8 || ma != 4 ) { + panic("Undefined IPI-LHF read!\n"); + } + else { +#ifdef IPI_DEBUG + printf("IPI-LHF read %lx\n",pib_off); +#endif + *(uint64_t *)dest = 0; // TODO for SM-VP + } + } + else { // upper half + if ( s != 1 || ma != 4 ) { + panic("Undefined PIB-UHF read!\n"); + } + else { +#ifdef IPI_DEBUG + printf("IPI-UHF read %lx\n",pib_off); +#endif + *(uint8_t *)dest = 0; // TODO for SM-VP + } + } + break; + } +} + +static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = get_vio(v->domain, v->vcpu_id); + if (vio == 0) { + panic("bad shared page: %lx", (unsigned long)vio); + } + p = &vio->vp_ioreq; + p->addr = pa; + p->size = s; + p->count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 1; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(iopacket_port(v->domain)); + vmx_wait_io(); + if(dir==IOREQ_READ){ //read + *val=p->u.data; + } + return; +} +#define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3)) + +static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = get_vio(v->domain, v->vcpu_id); + if (vio == 0) { + panic("bad shared page: %lx"); + } + p = &vio->vp_ioreq; + p->addr = TO_LEGACY_IO(pa&0x3ffffffUL); + p->size = s; + p->count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 0; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(iopacket_port(v->domain)); + + vmx_wait_io(); + if(dir==IOREQ_READ){ //read + *val=p->u.data; + } +#ifdef DEBUG_PCI + if(dir==IOREQ_WRITE) + if(p->addr == 0xcf8UL) + printk("Write 0xcf8, with val [0x%lx]\n", p->u.data); + else + if(p->addr == 0xcfcUL) + printk("Read 0xcfc, with val [0x%lx]\n", p->u.data); +#endif //DEBUG_PCI + return; +} + +static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir) +{ + struct virutal_platform_def *v_plat; + //mmio_type_t iot; + unsigned long iot; + iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT); + v_plat = vmx_vcpu_get_plat(vcpu); + + switch (iot) { + case GPFN_PIB: + if(!dir) + pib_write(vcpu, dest, src_pa - v_plat->pib_base, s, ma); + else + pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + break; + case GPFN_GFW: + break; + case GPFN_IOSAPIC: + case GPFN_FRAME_BUFFER: + case GPFN_LOW_MMIO: + low_mmio_access(vcpu, src_pa, dest, s, dir); + break; + case GPFN_LEGACY_IO: + legacy_io_access(vcpu, src_pa, dest, s, dir); + break; + default: + panic("Bad I/O access\n"); + break; + } + return; +} + +/* + * Read or write data in guest virtual address mode. + */ +/* +void +memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa; + + if (!vtlb->nomap) + panic("Normal memory write shouldn't go to this point!"); + pa = PPN_2_PA(vtlb->ppn); + pa += POFFSET((u64)dest, vtlb->ps); + mmio_write (vcpu, src, pa, s, vtlb->ma); +} + + +void +memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa = (uint64_t)dest; + int ma; + + if ( pa & (1UL <<63) ) { + // UC + ma = 4; + pa <<=1; + pa >>=1; + } + else { + // WBL + ma = 0; // using WB for WBL + } + mmio_write (vcpu, src, pa, s, ma); +} + +void +memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa; + + if (!vtlb->nomap) + panic("Normal memory write shouldn't go to this point!"); + pa = PPN_2_PA(vtlb->ppn); + pa += POFFSET((u64)src, vtlb->ps); + + mmio_read(vcpu, pa, dest, s, vtlb->ma); +} + +void +memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa = (uint64_t)src; + int ma; + + if ( pa & (1UL <<63) ) { + // UC + ma = 4; + pa <<=1; + pa >>=1; + } + else { + // WBL + ma = 0; // using WB for WBL + } + mmio_read(vcpu, pa, dest, s, ma); +} +*/ + + +/* + * Deliver IPI message. (Only U-VP is supported now) + * offset: address offset to IPI space. + * value: deliver value. + */ +static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) +{ +#ifdef IPI_DEBUG + printf ("deliver_ipi %lx %lx\n",dm,vector); +#endif + switch ( dm ) { + case 0: // INT + vmx_vcpu_pend_interrupt (vcpu, vector); + break; + case 2: // PMI + // TODO -- inject guest PMI + panic ("Inject guest PMI!\n"); + break; + case 4: // NMI + vmx_vcpu_pend_interrupt (vcpu, 2); + break; + case 5: // INIT + // TODO -- inject guest INIT + panic ("Inject guest INIT!\n"); + break; + case 7: // ExtINT + vmx_vcpu_pend_interrupt (vcpu, 0); + break; + case 1: + case 3: + case 6: + default: + panic ("Deliver reserved IPI!\n"); + break; + } +} + +/* + * TODO: Use hash table for the lookup. + */ +static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) +{ + int i; + VCPU *vcpu; + LID lid; + for (i=0; i<MAX_VIRT_CPUS; i++) { + vcpu = d->vcpu[i]; + if (!vcpu) + continue; + lid.val = VPD_CR(vcpu, lid); + if ( lid.id == id && lid.eid == eid ) { + return vcpu; + } + } + return NULL; +} + +/* + * execute write IPI op. + */ +static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) +{ + VCPU *target_cpu; + + target_cpu = lid_2_vcpu(vcpu->domain, + ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); + if ( target_cpu == NULL ) panic("Unknown IPI cpu\n"); + if ( target_cpu == vcpu ) { + // IPI to self + deliver_ipi (vcpu, ((ipi_d_t)value).dm, + ((ipi_d_t)value).vector); + return 1; + } + else { + // TODO: send Host IPI to inject guest SMP IPI interruption + panic ("No SM-VP supported!\n"); + return 0; + } +} + + +/* + dir 1: read 0:write + inst_type 0:integer 1:floating point + */ +extern IA64_BUNDLE __vmx_get_domain_bundle(u64 iip); +#define SL_INTEGER 0 // store/load interger +#define SL_FLOATING 1 // store/load floating + +void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) +{ + REGS *regs; + IA64_BUNDLE bundle; + int slot, dir, inst_type; + size_t size; + u64 data, value,post_update, slot1a, slot1b, temp; + INST64 inst; + regs=vcpu_regs(vcpu); + bundle = __vmx_get_domain_bundle(regs->cr_iip); + slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; + if (!slot) inst.inst = bundle.slot0; + else if (slot == 1){ + slot1a=bundle.slot1a; + slot1b=bundle.slot1b; + inst.inst =slot1a + (slot1b<<18); + } + else if (slot == 2) inst.inst = bundle.slot2; + + + // Integer Load/Store + if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){ + inst_type = SL_INTEGER; // + size=(inst.M1.x6&0x3); + if((inst.M1.x6>>2)>0xb){ // write + dir=IOREQ_WRITE; //write + vmx_vcpu_get_gr(vcpu,inst.M4.r2,&data); + }else if((inst.M1.x6>>2)<0xb){ // read + dir=IOREQ_READ; + vmx_vcpu_get_gr(vcpu,inst.M1.r1,&value); + } + } + // Integer Load + Reg update + else if(inst.M2.major==4&&inst.M2.m==1&&inst.M2.x==0){ + inst_type = SL_INTEGER; + dir = IOREQ_READ; //write + size = (inst.M2.x6&0x3); + vmx_vcpu_get_gr(vcpu,inst.M2.r1,&value); + vmx_vcpu_get_gr(vcpu,inst.M2.r3,&temp); + vmx_vcpu_get_gr(vcpu,inst.M2.r2,&post_update); + temp += post_update; + vmx_vcpu_set_gr(vcpu,inst.M2.r3,temp,0); + } + // Integer Load/Store + Imm update + else if(inst.M3.major==5){ + inst_type = SL_INTEGER; // + size=(inst.M3.x6&0x3); + if((inst.M5.x6>>2)>0xb){ // write + dir=IOREQ_WRITE; //write + vmx_vcpu_get_gr(vcpu,inst.M5.r2,&data); + vmx_vcpu_get_gr(vcpu,inst.M5.r3,&temp); + post_update = (inst.M5.i<<7)+inst.M5.imm7; + if(inst.M5.s) + temp -= post_update; + else + temp += post_update; + vmx_vcpu_set_gr(vcpu,inst.M5.r3,temp,0); + + }else if((inst.M3.x6>>2)<0xb){ // read + dir=IOREQ_READ; + vmx_vcpu_get_gr(vcpu,inst.M3.r1,&value); + vmx_vcpu_get_gr(vcpu,inst.M3.r3,&temp); + post_update = (inst.M3.i<<7)+inst.M3.imm7; + if(inst.M3.s) + temp -= post_update; + else + temp += post_update; + vmx_vcpu_set_gr(vcpu,inst.M3.r3,temp,0); + + } + } + // Floating-point Load/Store +// else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){ +// inst_type=SL_FLOATING; //fp +// dir=IOREQ_READ; +// size=3; //ldfd +// } + else{ + printf("This memory access instruction can't be emulated two: %lx\n ",inst.inst); + while(1); + } + + size = 1 << size; + if(dir==IOREQ_WRITE){ + mmio_access(vcpu, padr, &data, size, ma, dir); + }else{ + mmio_access(vcpu, padr, &data, size, ma, dir); + if(size==0) + data = (value & 0xffffffffffffff00U) | (data & 0xffU); + else if(size==1) + data = (value & 0xffffffffffff0000U) | (data & 0xffffU); + else if(size==2) + data = (value & 0xffffffff00000000U) | (data & 0xffffffffU); + + if(inst_type==SL_INTEGER){ //gp + vmx_vcpu_set_gr(vcpu,inst.M1.r1,data,0); + }else{ + panic("Don't support ldfd now !"); +/* switch(inst.M6.f1){ + + case 6: + regs->f6=(struct ia64_fpreg)data; + case 7: + regs->f7=(struct ia64_fpreg)data; + case 8: + regs->f8=(struct ia64_fpreg)data; + case 9: + regs->f9=(struct ia64_fpreg)data; + case 10: + regs->f10=(struct ia64_fpreg)data; + case 11: + regs->f11=(struct ia64_fpreg)data; + default : + ia64_ldfs(inst.M6.f1,&data); + } +*/ + } + } + vmx_vcpu_increment_iip(vcpu); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/pal_emul.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/pal_emul.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,280 @@ +/* + * PAL/SAL call delegation + * + * Copyright (c) 2004 Li Susie <susie.li@xxxxxxxxx> + * Copyright (c) 2005 Yu Ke <ke.yu@xxxxxxxxx> + * + * 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. + */ + +#include <asm/vmx_vcpu.h> + +static void +get_pal_parameters (VCPU *vcpu, UINT64 *gr29, + UINT64 *gr30, UINT64 *gr31) { + + vmx_vcpu_get_gr(vcpu,29,gr29); + vmx_vcpu_get_gr(vcpu,30,gr30); + vmx_vcpu_get_gr(vcpu,31,gr31); +} + +static void +set_pal_result (VCPU *vcpu,struct ia64_pal_retval result) { + + vmx_vcpu_set_gr(vcpu,8, result.status,0); + vmx_vcpu_set_gr(vcpu,9, result.v0,0); + vmx_vcpu_set_gr(vcpu,10, result.v1,0); + vmx_vcpu_set_gr(vcpu,11, result.v2,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); + vmx_vcpu_get_gr(vcpu,28,&gr28); + + /* Always call Host Pal in int=1 */ + gr30 = gr30 &(~(0x2UL)); + + /* call Host PAL cache flush */ + result=ia64_pal_call_static(gr28 ,gr29, gr30,gr31,1); // Clear psr.ic when call PAL_CACHE_FLUSH + + /* 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); +// } + while (result.status != 0) { + panic("PAL_CACHE_FLUSH ERROR, status %d", result.status); + } + + return result; +} + +static struct ia64_pal_retval +pal_vm_tr_read (VCPU *vcpu ) { +#warning pal_vm_tr_read: to be implemented + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + 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; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_platform_addr(VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= 0; //success + + return result; +} + +static struct ia64_pal_retval +pal_halt (VCPU *vcpu) { +#warning pal_halt: to be implemented + //bugbug: to be implement. + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + + +static struct ia64_pal_retval +pal_halt_light (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_read (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_write (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_bus_get_features(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_summary(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_init(VCPU *vcpu){ + struct ia64_pal_retval result; + result.status=0; + return result; +} + +static struct ia64_pal_retval +pal_cache_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_prot_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_shared_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_mem_attrib(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_debug_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_fixed_addr(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_base(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_ratios(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_halt_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_logical_to_physica(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_perf_mon_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_proc_get_features(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_ptce_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_register_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_rse_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_test_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_summary(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_page_size(VCPU *vcpu){ +} + +void +pal_emul( VCPU *vcpu) { + UINT64 gr28; + struct ia64_pal_retval result; + + + vmx_vcpu_get_gr(vcpu,28,&gr28); //bank1 + + 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; + + case PAL_CACHE_WRITE: + result = pal_cache_write (vcpu); + break; + + case PAL_PLATFORM_ADDR: + result = pal_platform_addr (vcpu); + break; + + default: + panic("pal_emul(): guest call unsupported pal" ); + } + set_pal_result (vcpu, result); +} + + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vlsapic.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vlsapic.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,620 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vlsapic.c: virtual lsapic model including ITC timer. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + */ + +#include <linux/sched.h> +#include <public/arch-ia64.h> +#include <asm/ia64_int.h> +#include <asm/vcpu.h> +#include <asm/regionreg.h> +#include <asm/tlb.h> +#include <asm/processor.h> +#include <asm/delay.h> +#include <asm/vmx_vcpu.h> +#include <asm/vmx_vcpu.h> +#include <asm/regs.h> +#include <asm/gcc_intrin.h> +#include <asm/vmx_mm_def.h> +#include <asm/vmx.h> +#include <asm/hw_irq.h> +#include <asm/vmx_pal_vsa.h> +#include <asm/kregs.h> + +#define SHARED_VLAPIC_INF +#ifdef V_IOSAPIC_READY +static inline vl_apic_info* get_psapic(VCPU *vcpu) +{ + shared_iopage_t *sp = get_sp(vcpu->domain); + return &(sp->vcpu_iodata[vcpu->vcpu_id].apic_intr); +} +#endif +//u64 fire_itc; +//u64 fire_itc2; +//u64 fire_itm; +//u64 fire_itm2; +/* + * Update the checked last_itc. + */ +static void update_last_itc(vtime_t *vtm, uint64_t cur_itc) +{ + vtm->last_itc = cur_itc; +} + +/* + * ITC value saw in guest (host+offset+drift). + */ +static uint64_t now_itc(vtime_t *vtm) +{ + uint64_t guest_itc=vtm->vtm_offset+ia64_get_itc(); + + if ( vtm->vtm_local_drift ) { +// guest_itc -= vtm->vtm_local_drift; + } + if ( (long)(guest_itc - vtm->last_itc) > 0 ) { + return guest_itc; + + } + else { + /* guest ITC backwarded due after LP switch */ + return vtm->last_itc; + } +} + +/* + * Interval time components reset. + */ +static void vtm_reset(VCPU *vcpu) +{ + uint64_t cur_itc; + vtime_t *vtm; + + vtm=&(vcpu->arch.arch_vmx.vtm); + vtm->vtm_offset = 0; + vtm->vtm_local_drift = 0; + VPD_CR(vcpu, itm) = 0; + VPD_CR(vcpu, itv) = 0x10000; + cur_itc = ia64_get_itc(); + vtm->last_itc = vtm->vtm_offset + cur_itc; +} + +/* callback function when vtm_timer expires */ +static void vtm_timer_fn(void *data) +{ + vtime_t *vtm; + VCPU *vcpu = data; + u64 cur_itc,vitm; + + UINT64 vec; + + vec = VPD_CR(vcpu, itv) & 0xff; + vmx_vcpu_pend_interrupt(vcpu, vec); + + vtm=&(vcpu->arch.arch_vmx.vtm); + cur_itc = now_itc(vtm); + vitm =VPD_CR(vcpu, itm); + //fire_itc2 = cur_itc; + //fire_itm2 = vitm; + update_last_itc(vtm,cur_itc); // pseudo read to update vITC +} + +void vtm_init(VCPU *vcpu) +{ + vtime_t *vtm; + uint64_t itc_freq; + + vtm=&(vcpu->arch.arch_vmx.vtm); + + itc_freq = local_cpu_data->itc_freq; + vtm->cfg_max_jump=itc_freq*MAX_JUMP_STEP/1000; + vtm->cfg_min_grun=itc_freq*MIN_GUEST_RUNNING_TIME/1000; + init_ac_timer(&vtm->vtm_timer, vtm_timer_fn, vcpu, 0); + vtm_reset(vcpu); +} + +/* + * Action when guest read ITC. + */ +uint64_t vtm_get_itc(VCPU *vcpu) +{ + uint64_t guest_itc, spsr; + vtime_t *vtm; + + vtm=&(vcpu->arch.arch_vmx.vtm); + // FIXME: should use local_irq_disable & local_irq_enable ?? + local_irq_save(spsr); + guest_itc = now_itc(vtm); +// update_last_itc(vtm, guest_itc); + + local_irq_restore(spsr); + return guest_itc; +} + +void vtm_set_itc(VCPU *vcpu, uint64_t new_itc) +{ + uint64_t spsr; + vtime_t *vtm; + + vtm=&(vcpu->arch.arch_vmx.vtm); + local_irq_save(spsr); + vtm->vtm_offset = new_itc - ia64_get_itc(); + vtm->last_itc = new_itc; + vtm_interruption_update(vcpu, vtm); + local_irq_restore(spsr); +} + +void vtm_set_itv(VCPU *vcpu) +{ + uint64_t spsr,itv; + vtime_t *vtm; + + vtm=&(vcpu->arch.arch_vmx.vtm); + local_irq_save(spsr); + itv = VPD_CR(vcpu, itv); + if ( ITV_IRQ_MASK(itv) ) + rem_ac_timer(&vtm->vtm_timer); + vtm_interruption_update(vcpu, vtm); + local_irq_restore(spsr); +} + + +/* + * Update interrupt or hook the vtm ac_timer for fire + * At this point vtm_timer should be removed if itv is masked. + */ +/* Interrupt must be disabled at this point */ + +extern u64 tick_to_ns(u64 tick); +#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ +void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm) +{ + uint64_t cur_itc,vitm,vitv; + uint64_t expires; + long diff_now, diff_last; + uint64_t spsr; + + vitv = VPD_CR(vcpu, itv); + if ( ITV_IRQ_MASK(vitv) ) { + return; + } + + vitm =VPD_CR(vcpu, itm); + local_irq_save(spsr); + cur_itc =now_itc(vtm); + diff_last = vtm->last_itc - vitm; + diff_now = cur_itc - vitm; + update_last_itc (vtm,cur_itc); + + if ( diff_last >= 0 ) { + // interrupt already fired. + rem_ac_timer(&vtm->vtm_timer); + } + else if ( diff_now >= 0 ) { + // ITV is fired. + vmx_vcpu_pend_interrupt(vcpu, vitv&0xff); + } + /* Both last_itc & cur_itc < itm, wait for fire condition */ + else { + expires = NOW() + tick_to_ns(0-diff_now) + TIMER_SLOP; + set_ac_timer(&vtm->vtm_timer, expires); + } + local_irq_restore(spsr); +} + +/* + * Action for vtm when the domain is scheduled out. + * Remove the ac_timer for vtm. + */ +void vtm_domain_out(VCPU *vcpu) +{ + if(!is_idle_task(vcpu->domain)) + rem_ac_timer(&vcpu->arch.arch_vmx.vtm.vtm_timer); +} + +/* + * Action for vtm when the domain is scheduled in. + * Fire vtm IRQ or add the ac_timer for vtm. + */ +void vtm_domain_in(VCPU *vcpu) +{ + vtime_t *vtm; + + if(!is_idle_task(vcpu->domain)) { + vtm=&(vcpu->arch.arch_vmx.vtm); + vtm_interruption_update(vcpu, vtm); + } +} + +/* + * Next for vLSapic + */ + +#define NMI_VECTOR 2 +#define ExtINT_VECTOR 0 +#define NULL_VECTOR -1 +#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.arch_vmx.in_service[i]) +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 / 16; + } + + VMX_VPD(vcpu,vhpi) = vhpi; + // TODO: Add support for XENO + if ( VMX_VPD(vcpu,vac).a_int ) { + ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, + (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); + } +} + +#ifdef V_IOSAPIC_READY +void vlapic_update_shared_info(VCPU *vcpu) +{ + //int i; + + vl_apic_info *ps; + + if (vcpu->domain == dom0) + return; + + ps = get_psapic(vcpu); + ps->vl_lapic_id = ((VPD_CR(vcpu, lid) >> 16) & 0xffff) << 16; + printf("vl_lapic_id = %x\n", ps->vl_lapic_id); + ps->vl_apr = 0; + // skip ps->vl_logical_dest && ps->vl_dest_format + // IPF support physical destination mode only + ps->vl_arb_id = 0; + /* + for ( i=0; i<4; i++ ) { + ps->tmr[i] = 0; // edge trigger + } + */ +} + +void vlapic_update_ext_irq(VCPU *vcpu) +{ + int vec; + + vl_apic_info *ps = get_psapic(vcpu); + while ( (vec = highest_bits(ps->irr)) != NULL_VECTOR ) { + clear_bit (vec, ps->irr); + vmx_vcpu_pend_interrupt(vcpu, vec); + } +} +#endif + +void vlsapic_reset(VCPU *vcpu) +{ + int i; +#ifdef V_IOSAPIC_READY + vl_apic_info *psapic; // shared lapic inf. +#endif + + VPD_CR(vcpu, lid) = ia64_getreg(_IA64_REG_CR_LID); + VPD_CR(vcpu, ivr) = 0; + VPD_CR(vcpu,tpr) = 0x10000; + VPD_CR(vcpu, eoi) = 0; + VPD_CR(vcpu, irr[0]) = 0; + VPD_CR(vcpu, irr[1]) = 0; + VPD_CR(vcpu, irr[2]) = 0; + VPD_CR(vcpu, irr[3]) = 0; + VPD_CR(vcpu, pmv) = 0x10000; + VPD_CR(vcpu, cmcv) = 0x10000; + VPD_CR(vcpu, lrr0) = 0x10000; // default reset value? + VPD_CR(vcpu, lrr1) = 0x10000; // default reset value? + update_vhpi(vcpu, NULL_VECTOR); + for ( i=0; i<4; i++) { + VLSAPIC_INSVC(vcpu,i) = 0; + } +#ifdef V_IOSAPIC_READY + vlapic_update_shared_info(vcpu); + //vlapic_update_shared_irr(vcpu); +#endif + DPRINTK("VLSAPIC inservice base=%lp\n", &VLSAPIC_INSVC(vcpu,0) ); +} + +/* + * Find highest signaled bits in 4 words (long). + * + * return 0-255: highest bits. + * -1 : Not found. + */ +static __inline__ int highest_bits(uint64_t *dat) +{ + uint64_t bits, bitnum; + int i; + + /* loop for all 256 bits */ + for ( i=3; i >= 0 ; i -- ) { + bits = dat[i]; + if ( bits ) { + bitnum = ia64_fls(bits); + return i*64+bitnum; + } + } + return NULL_VECTOR; +} + +/* + * Return 0-255 for pending irq. + * NULL_VECTOR: when no pending. + */ +static int highest_pending_irq(VCPU *vcpu) +{ + if ( VPD_CR(vcpu, irr[0]) & (1UL<<NMI_VECTOR) ) return NMI_VECTOR; + if ( VPD_CR(vcpu, irr[0]) & (1UL<<ExtINT_VECTOR) ) return ExtINT_VECTOR; + return highest_bits(&VPD_CR(vcpu, irr[0])); +} + +static int highest_inservice_irq(VCPU *vcpu) +{ + if ( VLSAPIC_INSVC(vcpu, 0) & (1UL<<NMI_VECTOR) ) return NMI_VECTOR; + if ( VLSAPIC_INSVC(vcpu, 0) & (1UL<<ExtINT_VECTOR) ) return ExtINT_VECTOR; + return highest_bits(&(VLSAPIC_INSVC(vcpu, 0))); +} + +/* + * The pending irq is higher than the inservice one. + * + */ +static int is_higher_irq(int pending, int inservice) +{ + return ( (pending >> 4) > (inservice>>4) || + ((pending != NULL_VECTOR) && (inservice == NULL_VECTOR)) ); +} + +static int is_higher_class(int pending, int mic) +{ + return ( (pending >> 4) > mic ); +} + +static int is_invalid_irq(int vec) +{ + return (vec == 1 || ((vec <= 14 && vec >= 3))); +} + +#define IRQ_NO_MASKED 0 +#define IRQ_MASKED_BY_VTPR 1 +#define IRQ_MASKED_BY_INSVC 2 // masked by inservice IRQ + +/* See Table 5-8 in SDM vol2 for the definition */ +static int +_xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) +{ + tpr_t vtpr; + uint64_t mmi; + + vtpr.val = VPD_CR(vcpu, tpr); + + if ( h_inservice == NMI_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + if ( h_pending == NMI_VECTOR ) { + // Non Maskable Interrupt + return IRQ_NO_MASKED; + } + if ( h_inservice == ExtINT_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + mmi = vtpr.mmi; + if ( h_pending == ExtINT_VECTOR ) { + if ( mmi ) { + // mask all external IRQ + return IRQ_MASKED_BY_VTPR; + } + else { + return IRQ_NO_MASKED; + } + } + + if ( is_higher_irq(h_pending, h_inservice) ) { + if ( !mmi && is_higher_class(h_pending, vtpr.mic) ) { + return IRQ_NO_MASKED; + } + else { + return IRQ_MASKED_BY_VTPR; + } + } + else { + return IRQ_MASKED_BY_INSVC; + } +} + +static int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +{ + int mask; + + mask = _xirq_masked(vcpu, h_pending, h_inservice); + return mask; +} + + +/* + * May come from virtualization fault or + * nested host interrupt. + */ +void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) +{ + uint64_t spsr; + + if (vector & ~0xff) { + DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n"); + return; + } + local_irq_save(spsr); + VPD_CR(vcpu,irr[vector>>6]) |= 1UL<<(vector&63); + //vlapic_update_shared_irr(vcpu); + local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; +} + +/* + * 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) +{ + uint64_t spsr; + int i; + + local_irq_save(spsr); + for (i=0 ; i<4; i++ ) { + VPD_CR(vcpu,irr[i]) |= pend_irr[i]; + } + //vlapic_update_shared_irr(vcpu); + local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; +} + +/* + * If the new pending interrupt is enabled and not masked, we directly inject + * it into the guest. Otherwise, we set the VHPI if vac.a_int=1 so that when + * the interrupt becomes unmasked, it gets injected. + * RETURN: + * TRUE: Interrupt is injected. + * FALSE: Not injected but may be in VHPI when vac.a_int=1 + * + * Optimization: We defer setting the VHPI until the EOI time, if a higher + * priority interrupt is in-service. The idea is to reduce the + * number of unnecessary calls to inject_vhpi. + */ +int vmx_check_pending_irq(VCPU *vcpu) +{ + uint64_t spsr, mask; + int h_pending, h_inservice; + int injected=0; + uint64_t isr; + IA64_PSR vpsr; + + local_irq_save(spsr); + h_pending = highest_pending_irq(vcpu); + if ( h_pending == NULL_VECTOR ) goto chk_irq_exit; + h_inservice = highest_inservice_irq(vcpu); + + vpsr.val = vmx_vcpu_get_psr(vcpu); + mask = irq_masked(vcpu, h_pending, h_inservice); + if ( vpsr.i && IRQ_NO_MASKED == mask ) { + isr = vpsr.val & IA64_PSR_RI; + if ( !vpsr.ic ) + panic("Interrupt when IC=0\n"); + vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ + injected = 1; + } + 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. + update_vhpi(vcpu,h_pending); + } + +chk_irq_exit: + local_irq_restore(spsr); + return injected; +} + +/* + * Only coming from virtualization fault. + */ +void guest_write_eoi(VCPU *vcpu) +{ + int vec; + uint64_t spsr; + + vec = highest_inservice_irq(vcpu); + if ( vec == NULL_VECTOR ) panic("Wrong vector to EOI\n"); + local_irq_save(spsr); + VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); + local_irq_restore(spsr); + VPD_CR(vcpu, eoi)=0; // overwrite the data + vmx_check_pending_irq(vcpu); +} + +uint64_t guest_read_vivr(VCPU *vcpu) +{ + int vec, next, h_inservice; + uint64_t spsr; + + local_irq_save(spsr); + 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); + return IA64_SPURIOUS_INT_VECTOR; + } + + VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63)); + VPD_CR(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63)); + update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write + //vlapic_update_shared_irr(vcpu); + local_irq_restore(spsr); + return (uint64_t)vec; +} + +static void generate_exirq(VCPU *vcpu) +{ + IA64_PSR vpsr; + uint64_t isr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + update_vhpi(vcpu, NULL_VECTOR); + isr = vpsr.val & IA64_PSR_RI; + if ( !vpsr.ic ) + panic("Interrupt when IC=0\n"); + vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ +} + +vhpi_detection(VCPU *vcpu) +{ + uint64_t threshold,vhpi; + tpr_t vtpr; + IA64_PSR vpsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + vtpr.val = VPD_CR(vcpu, tpr); + + threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; + vhpi = VMX_VPD(vcpu,vhpi); + if ( vhpi > threshold ) { + // interrupt actived + generate_exirq (vcpu); + } +} + +vmx_vexirq(VCPU *vcpu) +{ + static uint64_t vexirq_count=0; + + vexirq_count ++; + printk("Virtual ex-irq %ld\n", vexirq_count); + generate_exirq (vcpu); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmmu.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmmu.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,846 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmmu.c: virtual memory management unit components. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/tlb.h> +#include <asm/gcc_intrin.h> +#include <asm/vcpu.h> +#include <linux/interrupt.h> +#include <asm/vmx_vcpu.h> +#include <asm/vmx_mm_def.h> +#include <asm/vmx.h> +#include <asm/hw_irq.h> +#include <asm/vmx_pal_vsa.h> +#include <asm/kregs.h> + +/* + * Architecture ppn is in 4KB unit while XEN + * page may be different(1<<PAGE_SHIFT). + */ +static inline u64 arch_ppn_to_xen_ppn(u64 appn) +{ + return (appn << ARCH_PAGE_SHIFT) >> PAGE_SHIFT; +} + +static inline u64 xen_ppn_to_arch_ppn(u64 xppn) +{ + return (xppn << PAGE_SHIFT) >> ARCH_PAGE_SHIFT; +} + + +/* + * Get the machine page frame number in 16KB unit + * Input: + * d: + */ +u64 get_mfn(domid_t domid, u64 gpfn, u64 pages) +{ + struct domain *d; + u64 i, xen_gppn, xen_mppn, mpfn; + + if ( domid == DOMID_SELF ) { + d = current->domain; + } + else { + d = find_domain_by_id(domid); + } + xen_gppn = arch_ppn_to_xen_ppn(gpfn); + xen_mppn = __gpfn_to_mfn(d, xen_gppn); +/* + for (i=0; i<pages; i++) { + if ( __gpfn_to_mfn(d, gpfn+i) == INVALID_MFN ) { + return INVALID_MFN; + } + } +*/ + mpfn= xen_ppn_to_arch_ppn(xen_mppn); + mpfn = mpfn | (((1UL <<(PAGE_SHIFT-12))-1)&gpfn); + return mpfn; + +} + +/* + * The VRN bits of va stand for which rr to get. + */ +ia64_rr vmmu_get_rr(VCPU *vcpu, u64 va) +{ + ia64_rr vrr; + vmx_vcpu_get_rr(vcpu, va, &vrr.rrval); + return vrr; +} + + +void recycle_message(thash_cb_t *hcb, u64 para) +{ + printk("hcb=%p recycled with %lx\n",hcb,para); +} + + +/* + * Purge all guest TCs in logical processor. + * Instead of purging all LP TCs, we should only purge + * TCs that belong to this guest. + */ +void +purge_machine_tc_by_domid(domid_t domid) +{ +#ifndef PURGE_GUEST_TC_ONLY + // purge all TCs + struct ia64_pal_retval result; + u64 addr; + u32 count1,count2; + u32 stride1,stride2; + u32 i,j; + u64 psr; + + + result = ia64_pal_call_static(PAL_PTCE_INFO,0,0,0, 0); + if ( result.status != 0 ) { + panic ("PAL_PTCE_INFO failed\n"); + } + addr = result.v0; + count1 = HIGH_32BITS(result.v1); + count2 = LOW_32BITS (result.v1); + stride1 = HIGH_32BITS(result.v2); + stride2 = LOW_32BITS (result.v2); + + local_irq_save(psr); + for (i=0; i<count1; i++) { + for (j=0; j<count2; j++) { + ia64_ptce(addr); + addr += stride2; + } + addr += stride1; + } + local_irq_restore(psr); +#else + // purge all TCs belong to this guest. +#endif +} + +static thash_cb_t *init_domain_vhpt(struct vcpu *d) +{ + struct pfn_info *page; + void *vbase,*vcur; + vhpt_special *vs; + thash_cb_t *vhpt; + PTA pta_value; + + page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); + if ( page == NULL ) { + panic("No enough contiguous memory for init_domain_mm\n"); + } + vbase = page_to_virt(page); + printk("Allocate domain vhpt at 0x%lx\n", (u64)vbase); + memset(vbase, 0, VCPU_TLB_SIZE); + vcur = (void*)((u64)vbase + VCPU_TLB_SIZE); + vhpt = --((thash_cb_t*)vcur); + vhpt->ht = THASH_VHPT; + vhpt->vcpu = d; + vhpt->hash_func = machine_thash; + vs = --((vhpt_special *)vcur); + + /* Setup guest pta */ + pta_value.val = 0; + pta_value.ve = 1; + pta_value.vf = 1; + pta_value.size = VCPU_TLB_SHIFT - 1; /* 2M */ + pta_value.base = ((u64)vbase) >> PTA_BASE_SHIFT; + d->arch.arch_vmx.mpta = pta_value.val; + + vhpt->vs = vs; + vhpt->vs->get_mfn = get_mfn; + vhpt->vs->tag_func = machine_ttag; + vhpt->hash = vbase; + vhpt->hash_sz = VCPU_TLB_SIZE/2; + vhpt->cch_buf = (u64)vbase + vhpt->hash_sz; + vhpt->cch_sz = (u64)vcur - (u64)vhpt->cch_buf; + vhpt->recycle_notifier = recycle_message; + thash_init(vhpt,VCPU_TLB_SHIFT-1); + return vhpt; +} + + +thash_cb_t *init_domain_tlb(struct vcpu *d) +{ + struct pfn_info *page; + void *vbase,*vcur; + tlb_special_t *ts; + thash_cb_t *tlb; + + page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); + if ( page == NULL ) { + panic("No enough contiguous memory for init_domain_mm\n"); + } + vbase = page_to_virt(page); + printk("Allocate domain tlb at 0x%lx\n", (u64)vbase); + memset(vbase, 0, VCPU_TLB_SIZE); + vcur = (void*)((u64)vbase + VCPU_TLB_SIZE); + tlb = --((thash_cb_t*)vcur); + tlb->ht = THASH_TLB; + tlb->vcpu = d; + ts = --((tlb_special_t *)vcur); + tlb->ts = ts; + tlb->ts->vhpt = init_domain_vhpt(d); + tlb->hash_func = machine_thash; + tlb->hash = vbase; + tlb->hash_sz = VCPU_TLB_SIZE/2; + tlb->cch_buf = (u64)vbase + tlb->hash_sz; + tlb->cch_sz = (u64)vcur - (u64)tlb->cch_buf; + tlb->recycle_notifier = recycle_message; + thash_init(tlb,VCPU_TLB_SHIFT-1); + return tlb; +} + +/* Allocate physical to machine mapping table for domN + * FIXME: Later this interface may be removed, if that table is provided + * by control panel. Dom0 has gpfn identical to mfn, which doesn't need + * this interface at all. + */ +void +alloc_pmt(struct domain *d) +{ + struct pfn_info *page; + + /* Only called once */ + ASSERT(d->arch.pmt); + + page = alloc_domheap_pages(NULL, get_order(d->max_pages), 0); + ASSERT(page); + + d->arch.pmt = page_to_virt(page); + memset(d->arch.pmt, 0x55, d->max_pages * 8); +} + +/* + * Insert guest TLB to machine TLB. + * data: In TLB format + */ +void machine_tlb_insert(struct vcpu *d, thash_data_t *tlb) +{ + u64 saved_itir, saved_ifa, saved_rr; + u64 pages; + thash_data_t mtlb; + ia64_rr vrr; + unsigned int cl = tlb->cl; + + mtlb.ifa = tlb->vadr; + mtlb.itir = tlb->itir & ~ITIR_RV_MASK; + vrr = vmmu_get_rr(d,mtlb.ifa); + //vmx_vcpu_get_rr(d, mtlb.ifa, &vrr.value); + pages = PSIZE(vrr.ps) >> PAGE_SHIFT; + mtlb.page_flags = tlb->page_flags & ~PAGE_FLAGS_RV_MASK; + mtlb.ppn = get_mfn(DOMID_SELF,tlb->ppn, pages); + if (mtlb.ppn == INVALID_MFN) + panic("Machine tlb insert with invalid mfn number.\n"); + + __asm __volatile("rsm psr.ic|psr.i;; srlz.i" ); + + saved_itir = ia64_getreg(_IA64_REG_CR_ITIR); + saved_ifa = ia64_getreg(_IA64_REG_CR_IFA); + saved_rr = ia64_get_rr(mtlb.ifa); + + ia64_setreg(_IA64_REG_CR_ITIR, mtlb.itir); + ia64_setreg(_IA64_REG_CR_IFA, mtlb.ifa); + /* Only access memory stack which is mapped by TR, + * after rr is switched. + */ + ia64_set_rr(mtlb.ifa, vmx_vrrtomrr(d, vrr.rrval)); + ia64_srlz_d(); + if ( cl == ISIDE_TLB ) { + ia64_itci(mtlb.page_flags); + ia64_srlz_i(); + } + else { + ia64_itcd(mtlb.page_flags); + ia64_srlz_d(); + } + ia64_set_rr(mtlb.ifa,saved_rr); + ia64_srlz_d(); + ia64_setreg(_IA64_REG_CR_IFA, saved_ifa); + ia64_setreg(_IA64_REG_CR_ITIR, saved_itir); + __asm __volatile("ssm psr.ic|psr.i;; srlz.i" ); +} + +u64 machine_thash(PTA pta, u64 va, u64 rid, u64 ps) +{ + u64 saved_pta, saved_rr0; + u64 hash_addr, tag; + unsigned long psr; + struct vcpu *v = current; + ia64_rr vrr; + + + saved_pta = ia64_getreg(_IA64_REG_CR_PTA); + saved_rr0 = ia64_get_rr(0); + vrr.rrval = saved_rr0; + vrr.rid = rid; + vrr.ps = ps; + + va = (va << 3) >> 3; // set VRN to 0. + // TODO: Set to enforce lazy mode + local_irq_save(psr); + ia64_setreg(_IA64_REG_CR_PTA, pta.val); + ia64_set_rr(0, vmx_vrrtomrr(v, vrr.rrval)); + ia64_srlz_d(); + + hash_addr = ia64_thash(va); + ia64_setreg(_IA64_REG_CR_PTA, saved_pta); + + ia64_set_rr(0, saved_rr0); + ia64_srlz_d(); + local_irq_restore(psr); + return hash_addr; +} + +u64 machine_ttag(PTA pta, u64 va, u64 rid, u64 ps) +{ + u64 saved_pta, saved_rr0; + u64 hash_addr, tag; + u64 psr; + struct vcpu *v = current; + ia64_rr vrr; + + // TODO: Set to enforce lazy mode + saved_pta = ia64_getreg(_IA64_REG_CR_PTA); + saved_rr0 = ia64_get_rr(0); + vrr.rrval = saved_rr0; + vrr.rid = rid; + vrr.ps = ps; + + va = (va << 3) >> 3; // set VRN to 0. + local_irq_save(psr); + ia64_setreg(_IA64_REG_CR_PTA, pta.val); + ia64_set_rr(0, vmx_vrrtomrr(v, vrr.rrval)); + ia64_srlz_d(); + + tag = ia64_ttag(va); + ia64_setreg(_IA64_REG_CR_PTA, saved_pta); + + ia64_set_rr(0, saved_rr0); + ia64_srlz_d(); + local_irq_restore(psr); + return tag; +} + +/* + * Purge machine tlb. + * INPUT + * rr: guest rr. + * va: only bits 0:60 is valid + * size: bits format (1<<size) for the address range to purge. + * + */ +void machine_tlb_purge(u64 rid, u64 va, u64 ps) +{ + u64 saved_rr0; + u64 psr; + ia64_rr vrr; + + va = (va << 3) >> 3; // set VRN to 0. + saved_rr0 = ia64_get_rr(0); + vrr.rrval = saved_rr0; + vrr.rid = rid; + vrr.ps = ps; + local_irq_save(psr); + ia64_set_rr( 0, vmx_vrrtomrr(current,vrr.rrval) ); + ia64_srlz_d(); + ia64_ptcl(va, ps << 2); + ia64_set_rr( 0, saved_rr0 ); + ia64_srlz_d(); + local_irq_restore(psr); +} + + +int vhpt_enabled(VCPU *vcpu, uint64_t vadr, vhpt_ref_t ref) +{ + ia64_rr vrr; + PTA vpta; + IA64_PSR vpsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + vrr = vmx_vcpu_rr(vcpu, vadr); + vmx_vcpu_get_pta(vcpu,&vpta.val); + + if ( vrr.ve & vpta.ve ) { + switch ( ref ) { + case DATA_REF: + case NA_REF: + return vpsr.dt; + case INST_REF: + return vpsr.dt && vpsr.it && vpsr.ic; + case RSE_REF: + return vpsr.dt && vpsr.rt; + + } + } + return 0; +} + + +int unimplemented_gva(VCPU *vcpu,u64 vadr) +{ + int bit=vcpu->domain->arch.imp_va_msb; + u64 ladr =(vadr<<3)>>(3+bit); + if(!ladr||ladr==(1U<<(61-bit))-1){ + return 0; + }else{ + return 1; + } +} + + +/* + * Prefetch guest bundle code. + * INPUT: + * code: buffer pointer to hold the read data. + * num: number of dword (8byts) to read. + */ +int +fetch_code(VCPU *vcpu, u64 gip, u64 *code) +{ + u64 gpip; // guest physical IP + u64 mpa; + thash_data_t *tlb; + ia64_rr vrr; + u64 mfn; + + if ( !(VMX_VPD(vcpu, vpsr) & IA64_PSR_IT) ) { // I-side physical mode + gpip = gip; + } + else { + vmx_vcpu_get_rr(vcpu, gip, &vrr.rrval); + tlb = vtlb_lookup_ex (vmx_vcpu_get_vtlb(vcpu), + vrr.rid, gip, ISIDE_TLB ); + if ( tlb == NULL ) panic("No entry found in ITLB\n"); + gpip = (tlb->ppn << 12) | ( gip & (PSIZE(tlb->ps)-1) ); + } + mfn = __gpfn_to_mfn(vcpu->domain, gpip >>PAGE_SHIFT); + if ( mfn == INVALID_MFN ) return 0; + + mpa = (gpip & (PAGE_SIZE-1)) | (mfn<<PAGE_SHIFT); + *code = *(u64*)__va(mpa); + return 1; +} + +IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + + thash_data_t data, *ovl; + thash_cb_t *hcb; + search_section_t sections; + ia64_rr vrr; + + hcb = vmx_vcpu_get_vtlb(vcpu); + data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; + data.itir=itir; + data.vadr=PAGEALIGN(ifa,data.ps); + data.tc = 1; + data.cl=ISIDE_TLB; + vmx_vcpu_get_rr(vcpu, ifa, &vrr); + data.rid = vrr.rid; + + sections.tr = 1; + sections.tc = 0; + + ovl = thash_find_overlap(hcb, &data, sections); + while (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + thash_purge_and_insert(hcb, &data); + return IA64_NO_FAULT; +} + + + + +IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + + thash_data_t data, *ovl; + thash_cb_t *hcb; + search_section_t sections; + ia64_rr vrr; + + hcb = vmx_vcpu_get_vtlb(vcpu); + data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; + data.itir=itir; + data.vadr=PAGEALIGN(ifa,data.ps); + data.tc = 1; + data.cl=DSIDE_TLB; + vmx_vcpu_get_rr(vcpu, ifa, &vrr); + data.rid = vrr.rid; + sections.tr = 1; + sections.tc = 0; + + ovl = thash_find_overlap(hcb, &data, sections); + if (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + thash_purge_and_insert(hcb, &data); + return IA64_NO_FAULT; +} + +/* + * Return TRUE/FALSE for success of lock operation + */ +int vmx_lock_guest_dtc (VCPU *vcpu, UINT64 va, int lock) +{ + + thash_cb_t *hcb; + ia64_rr vrr; + u64 preferred_size; + + vmx_vcpu_get_rr(vcpu, va, &vrr); + hcb = vmx_vcpu_get_vtlb(vcpu); + va = PAGEALIGN(va,vrr.ps); + preferred_size = PSIZE(vrr.ps); + return thash_lock_tc(hcb, va, preferred_size, vrr.rid, DSIDE_TLB, lock); +} + +IA64FAULT vmx_vcpu_itr_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa, UINT64 idx) +{ + + thash_data_t data, *ovl; + thash_cb_t *hcb; + search_section_t sections; + ia64_rr vrr; + + hcb = vmx_vcpu_get_vtlb(vcpu); + data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; + data.itir=itir; + data.vadr=PAGEALIGN(ifa,data.ps); + data.tc = 0; + data.cl=ISIDE_TLB; + vmx_vcpu_get_rr(vcpu, ifa, &vrr); + data.rid = vrr.rid; + sections.tr = 1; + sections.tc = 0; + + ovl = thash_find_overlap(hcb, &data, sections); + if (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + sections.tr = 0; + sections.tc = 1; + thash_purge_entries(hcb, &data, sections); + thash_tr_insert(hcb, &data, ifa, idx); + return IA64_NO_FAULT; +} + +IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa, UINT64 idx) +{ + + thash_data_t data, *ovl; + thash_cb_t *hcb; + search_section_t sections; + ia64_rr vrr; + + + hcb = vmx_vcpu_get_vtlb(vcpu); + data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; + data.itir=itir; + data.vadr=PAGEALIGN(ifa,data.ps); + data.tc = 0; + data.cl=DSIDE_TLB; + vmx_vcpu_get_rr(vcpu, ifa, &vrr); + data.rid = vrr.rid; + sections.tr = 1; + sections.tc = 0; + + ovl = thash_find_overlap(hcb, &data, sections); + while (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + sections.tr = 0; + sections.tc = 1; + thash_purge_entries(hcb, &data, sections); + thash_tr_insert(hcb, &data, ifa, idx); + return IA64_NO_FAULT; +} + + + +IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 ps) +{ + thash_cb_t *hcb; + ia64_rr rr; + search_section_t sections; + + hcb = vmx_vcpu_get_vtlb(vcpu); + rr=vmx_vcpu_rr(vcpu,vadr); + sections.tr = 1; + sections.tc = 1; + thash_purge_entries_ex(hcb,rr.rid,vadr,ps,sections,DSIDE_TLB); + return IA64_NO_FAULT; +} + +IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 ps) +{ + thash_cb_t *hcb; + ia64_rr rr; + search_section_t sections; + hcb = vmx_vcpu_get_vtlb(vcpu); + rr=vmx_vcpu_rr(vcpu,vadr); + sections.tr = 1; + sections.tc = 1; + thash_purge_entries_ex(hcb,rr.rid,vadr,ps,sections,ISIDE_TLB); + return IA64_NO_FAULT; +} + +IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 ps) +{ + thash_cb_t *hcb; + ia64_rr vrr; + search_section_t sections; + thash_data_t data, *ovl; + hcb = vmx_vcpu_get_vtlb(vcpu); + vrr=vmx_vcpu_rr(vcpu,vadr); + sections.tr = 0; + sections.tc = 1; + vadr = PAGEALIGN(vadr, ps); + + thash_purge_entries_ex(hcb,vrr.rid,vadr,ps,sections,DSIDE_TLB); + thash_purge_entries_ex(hcb,vrr.rid,vadr,ps,sections,ISIDE_TLB); + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) +{ + thash_cb_t *hcb; + hcb = vmx_vcpu_get_vtlb(vcpu); + thash_purge_all(hcb); + return IA64_NO_FAULT; +} + +IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 ps) +{ + vmx_vcpu_ptc_l(vcpu, vadr, ps); + return IA64_ILLOP_FAULT; +} + +IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 ps) +{ + vmx_vcpu_ptc_l(vcpu, vadr, ps); + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval) +{ + PTA vpta; + ia64_rr vrr; + u64 vhpt_offset,tmp; + vmx_vcpu_get_pta(vcpu, &vpta.val); + vrr=vmx_vcpu_rr(vcpu, vadr); + if(vpta.vf){ + panic("THASH,Don't support long format VHPT"); + *pval = ia64_call_vsa(PAL_VPS_THASH,vadr,vrr.rrval,vpta.val,0,0,0,0); + }else{ + vhpt_offset=((vadr>>vrr.ps)<<3)&((1UL<<(vpta.size))-1); + *pval = (vadr&VRN_MASK)| + (vpta.val<<3>>(vpta.size+3)<<(vpta.size))| + vhpt_offset; + } + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval) +{ + ia64_rr vrr; + PTA vpta; + vmx_vcpu_get_pta(vcpu, &vpta.val); + vrr=vmx_vcpu_rr(vcpu, vadr); + if(vpta.vf){ + panic("THASH,Don't support long format VHPT"); + *pval = ia64_call_vsa(PAL_VPS_TTAG,vadr,vrr.rrval,0,0,0,0,0); + }else{ + *pval = 1; + } + return IA64_NO_FAULT; +} + + + +IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +{ + thash_data_t *data; + thash_cb_t *hcb; + ia64_rr vrr; + ISR visr,pt_isr; + REGS *regs; + u64 vhpt_adr; + IA64_PSR vpsr; + hcb = vmx_vcpu_get_vtlb(vcpu); + vrr=vmx_vcpu_rr(vcpu,vadr); + regs=vcpu_regs(vcpu); + pt_isr.val=regs->cr_isr; + visr.val=0; + visr.ei=pt_isr.ei; + visr.ir=pt_isr.ir; + vpsr.val = vmx_vcpu_get_psr(vcpu); + if(vpsr.ic==0){ + visr.ni=1; + } + visr.na=1; + data = vtlb_lookup_ex(hcb, vrr.rid, vadr, DSIDE_TLB); + if(data){ + if(data->p==0){ + visr.na=1; + vmx_vcpu_set_isr(vcpu,visr.val); + page_not_present(vcpu, vadr); + return IA64_FAULT; + }else if(data->ma == VA_MATTR_NATPAGE){ + visr.na = 1; + vmx_vcpu_set_isr(vcpu, visr.val); + dnat_page_consumption(vcpu, vadr); + return IA64_FAULT; + }else{ + *padr = (data->ppn<<12) | (vadr&(PSIZE(data->ps)-1)); + return IA64_NO_FAULT; + } + }else{ + if(!vhpt_enabled(vcpu, vadr, NA_REF)){ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, visr.val); + alt_dtlb(vcpu, vadr); + return IA64_FAULT; + } + else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + else{ + vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); + vrr=vmx_vcpu_rr(vcpu,vhpt_adr); + data = vtlb_lookup_ex(hcb, vrr.rid, vhpt_adr, DSIDE_TLB); + if(data){ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, visr.val); + dtlb_fault(vcpu, vadr); + return IA64_FAULT; + } + else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + else{ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, visr.val); + dvhpt_fault(vcpu, vadr); + return IA64_FAULT; + } + else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + } + } +} + +IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) +{ + thash_data_t *data; + thash_cb_t *hcb; + ia64_rr rr; + PTA vpta; + vmx_vcpu_get_pta(vcpu, &vpta.val); + if(vpta.vf==0 || unimplemented_gva(vcpu, vadr)){ + *key=1; + return IA64_NO_FAULT; + } + hcb = vmx_vcpu_get_vtlb(vcpu); + rr=vmx_vcpu_rr(vcpu,vadr); + data = vtlb_lookup_ex(hcb, rr.rid, vadr, DSIDE_TLB); + if(!data||!data->p){ + *key=1; + }else{ + *key=data->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; + thash_cb_t *vtlb; + unsigned long end; /* end of the area mapped by current entry */ + thash_data_t *entry; + struct vcpu *v = current; + ia64_rr vrr; + + vtlb = vmx_vcpu_get_vtlb(v); + vrr = vmx_vcpu_rr(v, va); + entry = vtlb_lookup_ex(vtlb, vrr.rid, 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 = __gpfn_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 -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_entry.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_entry.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,611 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_entry.S: + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) + * Kun Tian (Kevin Tian) (kevin.tian@xxxxxxxxx) + */ + +#ifndef VCPU_TLB_SHIFT +#define VCPU_TLB_SHIFT 22 +#endif +#include <linux/config.h> +#include <asm/asmmacro.h> +#include <asm/cache.h> +#include <asm/kregs.h> +#include <asm/offsets.h> +#include <asm/pgtable.h> +#include <asm/percpu.h> +#include <asm/processor.h> +#include <asm/thread_info.h> +#include <asm/unistd.h> + +#include "vmx_minstate.h" + +/* + * prev_task <- vmx_ia64_switch_to(struct task_struct *next) + * With Ingo's new scheduler, interrupts are disabled when this routine gets + * called. The code starting at .map relies on this. The rest of the code + * doesn't care about the interrupt masking status. + * + * Since we allocate domain stack in xenheap, there's no need to map new + * domain's stack since all xenheap is mapped by TR. Another different task + * for vmx_ia64_switch_to is to switch to bank0 and change current pointer. + */ +GLOBAL_ENTRY(vmx_ia64_switch_to) + .prologue + alloc r16=ar.pfs,1,0,0,0 + DO_SAVE_SWITCH_STACK + .body + + bsw.0 // Switch to bank0, because bank0 r21 is current pointer + ;; + adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 + movl r25=init_task + adds r26=IA64_TASK_THREAD_KSP_OFFSET,in0 + ;; + st8 [r22]=sp // save kernel stack pointer of old task + ;; + /* + * TR always mapped this task's page, we can skip doing it again. + */ + ld8 sp=[r26] // load kernel stack pointer of new task + mov r21=in0 // update "current" application register + mov r8=r13 // return pointer to previously running task + mov r13=in0 // set "current" pointer + ;; + bsw.1 + ;; + DO_LOAD_SWITCH_STACK + +#ifdef CONFIG_SMP + sync.i // ensure "fc"s done by this CPU are visible on other CPUs +#endif + br.ret.sptk.many rp // boogie on out in new context +END(vmx_ia64_switch_to) + +GLOBAL_ENTRY(ia64_leave_nested) + rsm psr.i + ;; + adds r21=PT(PR)+16,r12 + ;; + + lfetch [r21],PT(CR_IPSR)-PT(PR) + adds r2=PT(B6)+16,r12 + adds r3=PT(R16)+16,r12 + ;; + lfetch [r21] + ld8 r28=[r2],8 // load b6 + adds r29=PT(R24)+16,r12 + + ld8.fill r16=[r3] + adds r3=PT(AR_CSD)-PT(R16),r3 + adds r30=PT(AR_CCV)+16,r12 + ;; + ld8.fill r24=[r29] + ld8 r15=[r30] // load ar.ccv + ;; + ld8 r29=[r2],16 // load b7 + ld8 r30=[r3],16 // load ar.csd + ;; + ld8 r31=[r2],16 // load ar.ssd + ld8.fill r8=[r3],16 + ;; + ld8.fill r9=[r2],16 + ld8.fill r10=[r3],PT(R17)-PT(R10) + ;; + ld8.fill r11=[r2],PT(R18)-PT(R11) + ld8.fill r17=[r3],16 + ;; + ld8.fill r18=[r2],16 + ld8.fill r19=[r3],16 + ;; + ld8.fill r20=[r2],16 + ld8.fill r21=[r3],16 + mov ar.csd=r30 + mov ar.ssd=r31 + ;; + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + invala // invalidate ALAT + ;; + ld8.fill r22=[r2],24 + ld8.fill r23=[r3],24 + mov b6=r28 + ;; + ld8.fill r25=[r2],16 + ld8.fill r26=[r3],16 + mov b7=r29 + ;; + ld8.fill r27=[r2],16 + ld8.fill r28=[r3],16 + ;; + ld8.fill r29=[r2],16 + ld8.fill r30=[r3],24 + ;; + ld8.fill r31=[r2],PT(F9)-PT(R31) + adds r3=PT(F10)-PT(F6),r3 + ;; + ldf.fill f9=[r2],PT(F6)-PT(F9) + ldf.fill f10=[r3],PT(F8)-PT(F10) + ;; + ldf.fill f6=[r2],PT(F7)-PT(F6) + ;; + ldf.fill f7=[r2],PT(F11)-PT(F7) + ldf.fill f8=[r3],32 + ;; + srlz.i // ensure interruption collection is off + mov ar.ccv=r15 + ;; + bsw.0 // switch back to bank 0 (no stop bit required beforehand...) + ;; + ldf.fill f11=[r2] +// mov r18=r13 +// mov r21=r13 + adds r16=PT(CR_IPSR)+16,r12 + adds r17=PT(CR_IIP)+16,r12 + ;; + ld8 r29=[r16],16 // load cr.ipsr + ld8 r28=[r17],16 // load cr.iip + ;; + ld8 r30=[r16],16 // load cr.ifs + ld8 r25=[r17],16 // load ar.unat + ;; + ld8 r26=[r16],16 // load ar.pfs + ld8 r27=[r17],16 // load ar.rsc + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs + ;; + ld8 r24=[r16],16 // load ar.rnat (may be garbage) + ld8 r23=[r17],16// load ar.bspstore (may be garbage) + ;; + ld8 r31=[r16],16 // load predicates + ld8 r22=[r17],16 // load b0 + ;; + ld8 r19=[r16],16 // load ar.rsc value for "loadrs" + ld8.fill r1=[r17],16 // load r1 + ;; + ld8.fill r12=[r16],16 + ld8.fill r13=[r17],16 + ;; + ld8 r20=[r16],16 // ar.fpsr + ld8.fill r15=[r17],16 + ;; + ld8.fill r14=[r16],16 + ld8.fill r2=[r17] + ;; + ld8.fill r3=[r16] + ;; + mov r16=ar.bsp // get existing backing store pointer + ;; + mov b0=r22 + mov ar.pfs=r26 + mov cr.ifs=r30 + mov cr.ipsr=r29 + mov ar.fpsr=r20 + mov cr.iip=r28 + ;; + mov ar.rsc=r27 + mov ar.unat=r25 + mov pr=r31,-1 + rfi +END(ia64_leave_nested) + + + +GLOBAL_ENTRY(ia64_leave_hypervisor) + PT_REGS_UNWIND_INFO(0) + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to + ;; + * user- or fsys-mode, hence we disable interrupts early on: + */ + rsm psr.i + ;; + alloc loc0=ar.pfs,0,1,1,0 + adds out0=16,r12 + ;; + br.call.sptk.many b0=leave_hypervisor_tail + mov ar.pfs=loc0 + adds r8=IA64_VPD_BASE_OFFSET,r13 + ;; + ld8 r8=[r8] + ;; + adds r9=VPD(VPSR),r8 + ;; + ld8 r9=[r9] + ;; + tbit.z pBN0,pBN1=r9,IA64_PSR_BN_BIT + ;; +(pBN0) add r7=VPD(VBNAT),r8; +(pBN1) add r7=VPD(VNAT),r8; + ;; + ld8 r7=[r7] + ;; + mov ar.unat=r7 +(pBN0) add r4=VPD(VBGR),r8; +(pBN1) add r4=VPD(VGR),r8; +(pBN0) add r5=VPD(VBGR)+0x8,r8; +(pBN1) add r5=VPD(VGR)+0x8,r8; + ;; + ld8.fill r16=[r4],16 + ld8.fill r17=[r5],16 + ;; + ld8.fill r18=[r4],16 + ld8.fill r19=[r5],16 + ;; + ld8.fill r20=[r4],16 + ld8.fill r21=[r5],16 + ;; + ld8.fill r22=[r4],16 + ld8.fill r23=[r5],16 + ;; + ld8.fill r24=[r4],16 + ld8.fill r25=[r5],16 + ;; + ld8.fill r26=[r4],16 + ld8.fill r27=[r5],16 + ;; + ld8.fill r28=[r4],16 + ld8.fill r29=[r5],16 + ;; + ld8.fill r30=[r4],16 + ld8.fill r31=[r5],16 + ;; + bsw.0 + ;; + mov r18=r8 //vpd + mov r19=r9 //vpsr + adds r20=PT(PR)+16,r12 + ;; + lfetch [r20],PT(CR_IPSR)-PT(PR) + adds r16=PT(B6)+16,r12 + adds r17=PT(B7)+16,r12 + ;; + lfetch [r20] + mov r21=r13 // get current + ;; + ld8 r30=[r16],16 // load b6 + ld8 r31=[r17],16 // load b7 + add r20=PT(EML_UNAT)+16,r12 + ;; + ld8 r29=[r20] //load ar_unat + mov b6=r30 + mov b7=r31 + ld8 r30=[r16],16 //load ar_csd + ld8 r31=[r17],16 //load ar_ssd + ;; + mov ar.unat=r29 + mov ar.csd=r30 + mov ar.ssd=r31 + ;; + ld8.fill r8=[r16],16 //load r8 + ld8.fill r9=[r17],16 //load r9 + ;; + ld8.fill r10=[r16],PT(R1)-PT(R10) //load r10 + ld8.fill r11=[r17],PT(R12)-PT(R11) //load r11 + ;; + ld8.fill r1=[r16],16 //load r1 + ld8.fill r12=[r17],16 //load r12 + ;; + ld8.fill r13=[r16],16 //load r13 + ld8 r30=[r17],16 //load ar_fpsr + ;; + ld8.fill r15=[r16],16 //load r15 + ld8.fill r14=[r17],16 //load r14 + mov ar.fpsr=r30 + ;; + ld8.fill r2=[r16],16 //load r2 + ld8.fill r3=[r17],16 //load r3 + ;; +/* +(pEml) ld8.fill r4=[r16],16 //load r4 +(pEml) ld8.fill r5=[r17],16 //load r5 + ;; +(pEml) ld8.fill r6=[r16],PT(AR_CCV)-PT(R6) //load r6 +(pEml) ld8.fill r7=[r17],PT(F7)-PT(R7) //load r7 + ;; +(pNonEml) adds r16=PT(AR_CCV)-PT(R4),r16 +(pNonEml) adds r17=PT(F7)-PT(R5),r17 + ;; +*/ + ld8.fill r4=[r16],16 //load r4 + ld8.fill r5=[r17],16 //load r5 + ;; + ld8.fill r6=[r16],PT(AR_CCV)-PT(R6) //load r6 + ld8.fill r7=[r17],PT(F7)-PT(R7) //load r7 + ;; + + ld8 r30=[r16],PT(F6)-PT(AR_CCV) + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + ;; + srlz.i // ensure interruption collection is off + ;; + invala // invalidate ALAT + ;; + ldf.fill f6=[r16],32 + ldf.fill f7=[r17],32 + ;; + ldf.fill f8=[r16],32 + ldf.fill f9=[r17],32 + ;; + ldf.fill f10=[r16] + ldf.fill f11=[r17] + ;; + mov ar.ccv=r30 + adds r16=PT(CR_IPSR)-PT(F10),r16 + adds r17=PT(CR_IIP)-PT(F11),r17 + ;; + ld8 r31=[r16],16 // load cr.ipsr + ld8 r30=[r17],16 // load cr.iip + ;; + ld8 r29=[r16],16 // load cr.ifs + ld8 r28=[r17],16 // load ar.unat + ;; + ld8 r27=[r16],16 // load ar.pfs + ld8 r26=[r17],16 // load ar.rsc + ;; + ld8 r25=[r16],16 // load ar.rnat (may be garbage) + ld8 r24=[r17],16// load ar.bspstore (may be garbage) + ;; + ld8 r23=[r16],16 // load predicates + ld8 r22=[r17],PT(RFI_PFS)-PT(B0) // load b0 + ;; + ld8 r20=[r16],16 // load ar.rsc value for "loadrs" + ;; +//rbs_switch + // loadrs has already been shifted + alloc r16=ar.pfs,0,0,0,0 // drop current register frame + ;; + mov ar.rsc=r20 + ;; + loadrs + ;; + mov ar.bspstore=r24 + ;; + ld8 r24=[r17] //load rfi_pfs + mov ar.unat=r28 + mov ar.rnat=r25 + mov ar.rsc=r26 + ;; + mov cr.ipsr=r31 + mov cr.iip=r30 + mov cr.ifs=r29 + cmp.ne p6,p0=r24,r0 +(p6)br.sptk vmx_dorfirfi + ;; +vmx_dorfirfi_back: + mov ar.pfs=r27 + +//vsa_sync_write_start + movl r20=__vsa_base + ;; + ld8 r20=[r20] // read entry point + mov r25=r18 + ;; + add r16=PAL_VPS_SYNC_WRITE,r20 + movl r24=switch_rr7 // calculate return address + ;; + mov b0=r16 + br.cond.sptk b0 // call the service + ;; +// switch rr7 and rr5 +switch_rr7: + adds r24=SWITCH_MRR5_OFFSET, r21 + adds r26=SWITCH_MRR6_OFFSET, r21 + adds r16=SWITCH_MRR7_OFFSET ,r21 + movl r25=(5<<61) + movl r27=(6<<61) + movl r17=(7<<61) + ;; + ld8 r24=[r24] + ld8 r26=[r26] + ld8 r16=[r16] + ;; + mov rr[r25]=r24 + mov rr[r27]=r26 + mov rr[r17]=r16 + ;; + srlz.i + ;; + add r24=SWITCH_MPTA_OFFSET, r21 + ;; + ld8 r24=[r24] + ;; + mov cr.pta=r24 + ;; + srlz.i + ;; +// fall through +GLOBAL_ENTRY(ia64_vmm_entry) +/* + * must be at bank 0 + * parameter: + * r18:vpd + * r19:vpsr + * r20:__vsa_base + * r22:b0 + * r23:predicate + */ + mov r24=r22 + mov r25=r18 + tbit.nz p1,p2 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic + ;; + (p1) add r29=PAL_VPS_RESUME_NORMAL,r20 + (p2) add r29=PAL_VPS_RESUME_HANDLER,r20 + ;; + mov pr=r23,-2 + mov b0=r29 + ;; + br.cond.sptk b0 // call pal service +END(ia64_leave_hypervisor) + +//r24 rfi_pfs +//r17 address of rfi_pfs +GLOBAL_ENTRY(vmx_dorfirfi) + mov r16=ar.ec + movl r20 = vmx_dorfirfi_back + ;; +// clean rfi_pfs + st8 [r17]=r0 + mov b0=r20 +// pfs.pec=ar.ec + dep r24 = r16, r24, 52, 6 + ;; + mov ar.pfs=r24 + ;; + br.ret.sptk b0 + ;; +END(vmx_dorfirfi) + + +#define VMX_PURGE_RR7 0 +#define VMX_INSERT_RR7 1 +/* + * in0: old rr7 + * in1: virtual address of xen image + * in2: virtual address of vhpt table + */ +GLOBAL_ENTRY(vmx_purge_double_mapping) + alloc loc1 = ar.pfs,5,9,0,0 + mov loc0 = rp + movl r8 = 1f + ;; + movl loc4 = KERNEL_TR_PAGE_SHIFT + movl loc5 = VCPU_TLB_SHIFT + mov loc6 = psr + movl loc7 = XEN_RR7_SWITCH_STUB + mov loc8 = (1<<VMX_PURGE_RR7) + ;; + srlz.i + ;; + rsm psr.i | psr.ic + ;; + srlz.i + ;; + mov ar.rsc = 0 + mov b6 = loc7 + mov rp = r8 + ;; + br.sptk b6 +1: + mov ar.rsc = 3 + mov rp = loc0 + ;; + mov psr.l = loc6 + ;; + srlz.i + ;; + br.ret.sptk rp +END(vmx_purge_double_mapping) + +/* + * in0: new rr7 + * in1: virtual address of xen image + * in2: virtual address of vhpt table + * in3: pte entry of xen image + * in4: pte entry of vhpt table + */ +GLOBAL_ENTRY(vmx_insert_double_mapping) + alloc loc1 = ar.pfs,5,9,0,0 + mov loc0 = rp + movl loc2 = IA64_TR_XEN_IN_DOM // TR number for xen image + ;; + movl loc3 = IA64_TR_VHPT_IN_DOM // TR number for vhpt table + movl r8 = 1f + movl loc4 = KERNEL_TR_PAGE_SHIFT + ;; + movl loc5 = VCPU_TLB_SHIFT + mov loc6 = psr + movl loc7 = XEN_RR7_SWITCH_STUB + ;; + srlz.i + ;; + rsm psr.i | psr.ic + mov loc8 = (1<<VMX_INSERT_RR7) + ;; + srlz.i + ;; + mov ar.rsc = 0 + mov b6 = loc7 + mov rp = r8 + ;; + br.sptk b6 +1: + mov ar.rsc = 3 + mov rp = loc0 + ;; + mov psr.l = loc6 + ;; + srlz.i + ;; + br.ret.sptk rp +END(vmx_insert_double_mapping) + + .align PAGE_SIZE +/* + * Stub to add double mapping for new domain, which shouldn't + * access any memory when active. Before reaching this point, + * both psr.i/ic is cleared and rse is set in lazy mode. + * + * in0: new rr7 + * in1: virtual address of xen image + * in2: virtual address of vhpt table + * in3: pte entry of xen image + * in4: pte entry of vhpt table + * loc2: TR number for xen image + * loc3: TR number for vhpt table + * loc4: page size for xen image + * loc5: page size of vhpt table + * loc7: free to use + * loc8: purge or insert + * r8: will contain old rid value + */ +GLOBAL_ENTRY(vmx_switch_rr7) + movl loc7 = (7<<61) + dep.z loc4 = loc4, 2, 6 + dep.z loc5 = loc5, 2, 6 + ;; + tbit.nz p6,p7=loc8, VMX_INSERT_RR7 + mov r8 = rr[loc7] + ;; + mov rr[loc7] = in0 +(p6)mov cr.ifa = in1 +(p6)mov cr.itir = loc4 + ;; + srlz.i + ;; +(p6)itr.i itr[loc2] = in3 +(p7)ptr.i in1, loc4 + ;; +(p6)itr.d dtr[loc2] = in3 +(p7)ptr.d in1, loc4 + ;; + srlz.i + ;; +(p6)mov cr.ifa = in2 +(p6)mov cr.itir = loc5 + ;; +(p6)itr.d dtr[loc3] = in4 +(p7)ptr.d in2, loc5 + ;; + srlz.i + ;; + mov rr[loc7] = r8 + ;; + srlz.i + br.sptk rp +END(vmx_switch_rr7) + .align PAGE_SIZE diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_hypercall.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_hypercall.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,235 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_hyparcall.c: handling hypercall from domain + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <xen/config.h> +#include <xen/errno.h> +#include <asm/vmx_vcpu.h> +#include <public/xen.h> +#include <public/event_channel.h> +#include <asm/vmmu.h> +#include <asm/tlb.h> +#include <asm/regionreg.h> +#include <asm/page.h> +#include <xen/mm.h> +#include <xen/multicall.h> + + +void hyper_not_support(void) +{ + VCPU *vcpu=current; + vmx_vcpu_set_gr(vcpu, 8, -1, 0); + vmx_vcpu_increment_iip(vcpu); +} + +void hyper_mmu_update(void) +{ + VCPU *vcpu=current; + u64 r32,r33,r34,r35,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + vmx_vcpu_get_gr(vcpu,17,&r33); + vmx_vcpu_get_gr(vcpu,18,&r34); + vmx_vcpu_get_gr(vcpu,19,&r35); + ret=do_mmu_update((mmu_update_t*)r32,r33,r34,r35); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + vmx_vcpu_increment_iip(vcpu); +} + +unsigned long __hypercall_create_continuation( + unsigned int op, unsigned int nr_args, ...) +{ + struct mc_state *mcs = &mc_state[smp_processor_id()]; + VCPU *vcpu = current; + struct cpu_user_regs *regs = vcpu_regs(vcpu); + unsigned int i; + va_list args; + + va_start(args, nr_args); + if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { + panic("PREEMPT happen in multicall\n"); // Not support yet + } else { + vmx_vcpu_set_gr(vcpu, 15, op, 0); + for ( i = 0; i < nr_args; i++) { + switch (i) { + case 0: vmx_vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0); + break; + case 1: vmx_vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0); + break; + case 2: vmx_vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0); + break; + case 3: vmx_vcpu_set_gr(vcpu, 19, va_arg(args, unsigned long), 0); + break; + case 4: vmx_vcpu_set_gr(vcpu, 20, va_arg(args, unsigned long), 0); + break; + default: panic("Too many args for hypercall continuation\n"); + break; + } + } + } + vcpu->arch.hypercall_continuation = 1; + va_end(args); + return op; +} + +void hyper_dom_mem_op(void) +{ + VCPU *vcpu=current; + u64 r32,r33,r34,r35,r36; + u64 ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + vmx_vcpu_get_gr(vcpu,17,&r33); + vmx_vcpu_get_gr(vcpu,18,&r34); + vmx_vcpu_get_gr(vcpu,19,&r35); + vmx_vcpu_get_gr(vcpu,20,&r36); + ret=do_dom_mem_op(r32,(u64 *)r33,r34,r35,r36); + printf("do_dom_mem return value: %lx\n", ret); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + + /* Hard to define a special return value to indicate hypercall restart. + * So just add a new mark, which is SMP safe + */ + if (vcpu->arch.hypercall_continuation == 1) + vcpu->arch.hypercall_continuation = 0; + else + vmx_vcpu_increment_iip(vcpu); +} + + +void hyper_sched_op(void) +{ + VCPU *vcpu=current; + u64 r32,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + ret=do_sched_op(r32); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + + vmx_vcpu_increment_iip(vcpu); +} + +void hyper_dom0_op(void) +{ + VCPU *vcpu=current; + u64 r32,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + ret=do_dom0_op((dom0_op_t *)r32); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + + vmx_vcpu_increment_iip(vcpu); +} + +void hyper_event_channel_op(void) +{ + VCPU *vcpu=current; + u64 r32,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + ret=do_event_channel_op((evtchn_op_t *)r32); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + vmx_vcpu_increment_iip(vcpu); +} + +void hyper_xen_version(void) +{ + VCPU *vcpu=current; + u64 r32,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + ret=do_xen_version((int )r32); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + vmx_vcpu_increment_iip(vcpu); +} + +static int do_lock_page(VCPU *vcpu, u64 va, u64 lock) +{ + int i; + ia64_rr rr; + thash_cb_t *hcb; + hcb = vmx_vcpu_get_vtlb(vcpu); + rr = vmx_vcpu_rr(vcpu, va); + return thash_lock_tc(hcb, va ,1U<<rr.ps, rr.rid, DSIDE_TLB, lock); +} + +/* + * Lock guest page in vTLB, so that it's not relinquished by recycle + * session when HV is servicing that hypercall. + */ +void hyper_lock_page(void) +{ +//TODO: + VCPU *vcpu=current; + u64 va,lock, ret; + vmx_vcpu_get_gr(vcpu,16,&va); + vmx_vcpu_get_gr(vcpu,17,&lock); + ret=do_lock_page(vcpu, va, lock); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + + vmx_vcpu_increment_iip(vcpu); +} + +static int do_set_shared_page(VCPU *vcpu, u64 gpa) +{ + u64 shared_info, o_info; + struct domain *d = vcpu->domain; + struct vcpu *v; + if(vcpu->domain!=dom0) + return -EPERM; + shared_info = __gpa_to_mpa(vcpu->domain, gpa); + o_info = (u64)vcpu->domain->shared_info; + d->shared_info= (shared_info_t *)__va(shared_info); + + /* Copy existing shared info into new page */ + if (o_info) { + memcpy((void*)d->shared_info, (void*)o_info, PAGE_SIZE); + for_each_vcpu(d, v) { + v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; + } + /* If original page belongs to xen heap, then relinguish back + * to xen heap. Or else, leave to domain itself to decide. + */ + if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) + free_xenheap_page(o_info); + } else + memset(d->shared_info, 0, PAGE_SIZE); + return 0; +} + +void hyper_set_shared_page(void) +{ + VCPU *vcpu=current; + u64 gpa,ret; + vmx_vcpu_get_gr(vcpu,16,&gpa); + + ret=do_set_shared_page(vcpu, gpa); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); + + vmx_vcpu_increment_iip(vcpu); +} + +/* +void hyper_grant_table_op(void) +{ + VCPU *vcpu=current; + u64 r32,r33,r34,ret; + vmx_vcpu_get_gr(vcpu,16,&r32); + vmx_vcpu_get_gr(vcpu,17,&r33); + vmx_vcpu_get_gr(vcpu,18,&r34); + + ret=do_grant_table_op((unsigned int)r32, (void *)r33, (unsigned int)r34); + vmx_vcpu_set_gr(vcpu, 8, ret, 0); +} +*/ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_init.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_init.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,375 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_init.c: initialization work for vt specific domain + * Copyright (c) 2005, Intel Corporation. + * Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) <anthony.xu@xxxxxxxxx> + * Fred Yang <fred.yang@xxxxxxxxx> + * + * 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. + * + */ + +/* + * 05/08/16 Kun tian (Kevin Tian) <kevin.tian@xxxxxxxxx>: + * Disable doubling mapping + * + * 05/03/23 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx>: + * Simplied design in first step: + * - One virtual environment + * - Domain is bound to one LP + * Later to support guest SMP: + * - Need interface to handle VP scheduled to different LP + */ +#include <xen/config.h> +#include <xen/types.h> +#include <xen/sched.h> +#include <asm/pal.h> +#include <asm/page.h> +#include <asm/processor.h> +#include <asm/vmx_vcpu.h> +#include <xen/lib.h> +#include <asm/vmmu.h> +#include <public/arch-ia64.h> +#include <public/io/ioreq.h> +#include <asm/vmx_phy_mode.h> +#include <asm/processor.h> +#include <asm/vmx.h> +#include <xen/mm.h> + +/* Global flag to identify whether Intel vmx feature is on */ +u32 vmx_enabled = 0; +static u32 vm_order; +static u64 buffer_size; +static u64 vp_env_info; +static u64 vm_buffer = 0; /* Buffer required to bring up VMX feature */ +u64 __vsa_base = 0; /* Run-time service base of VMX */ + +/* Check whether vt feature is enabled or not. */ +void +identify_vmx_feature(void) +{ + pal_status_t ret; + u64 avail = 1, status = 1, control = 1; + + vmx_enabled = 0; + /* Check VT-i feature */ + ret = ia64_pal_proc_get_features(&avail, &status, &control); + if (ret != PAL_STATUS_SUCCESS) { + printk("Get proc features failed.\n"); + goto no_vti; + } + + /* FIXME: do we need to check status field, to see whether + * PSR.vm is actually enabled? If yes, aonther call to + * ia64_pal_proc_set_features may be reuqired then. + */ + printk("avail:0x%lx, status:0x%lx,control:0x%lx, vm?0x%lx\n", + avail, status, control, avail & PAL_PROC_VM_BIT); + if (!(avail & PAL_PROC_VM_BIT)) { + printk("No VT feature supported.\n"); + goto no_vti; + } + + ret = ia64_pal_vp_env_info(&buffer_size, &vp_env_info); + if (ret != PAL_STATUS_SUCCESS) { + printk("Get vp environment info failed.\n"); + goto no_vti; + } + + /* Does xen has ability to decode itself? */ + if (!(vp_env_info & VP_OPCODE)) + printk("WARNING: no opcode provided from hardware(%lx)!!!\n", vp_env_info); + vm_order = get_order(buffer_size); + printk("vm buffer size: %d, order: %d\n", buffer_size, vm_order); + + vmx_enabled = 1; +no_vti: + return; +} + +/* + * Init virtual environment on current LP + * vsa_base is the indicator whether it's first LP to be initialized + * for current domain. + */ +void +vmx_init_env(void) +{ + u64 status, tmp_base; + + if (!vm_buffer) { + vm_buffer = alloc_xenheap_pages(vm_order); + ASSERT(vm_buffer); + printk("vm_buffer: 0x%lx\n", vm_buffer); + } + + status=ia64_pal_vp_init_env(__vsa_base ? VP_INIT_ENV : VP_INIT_ENV_INITALIZE, + __pa(vm_buffer), + vm_buffer, + &tmp_base); + + if (status != PAL_STATUS_SUCCESS) { + printk("ia64_pal_vp_init_env failed.\n"); + return -1; + } + + if (!__vsa_base) + __vsa_base = tmp_base; + else + ASSERT(tmp_base != __vsa_base); + +#ifdef XEN_DBL_MAPPING + /* Init stub for rr7 switch */ + vmx_init_double_mapping_stub(); +#endif +} + +void vmx_setup_platform(struct vcpu *v, struct vcpu_guest_context *c) +{ + struct domain *d = v->domain; + shared_iopage_t *sp; + + ASSERT(d != dom0); /* only for non-privileged vti domain */ + d->arch.vmx_platform.shared_page_va = __va(c->share_io_pg); + sp = get_sp(d); + memset((char *)sp,0,PAGE_SIZE); + /* FIXME: temp due to old CP */ + sp->sp_global.eport = 2; +#ifdef V_IOSAPIC_READY + sp->vcpu_number = 1; +#endif + /* TEMP */ + d->arch.vmx_platform.pib_base = 0xfee00000UL; + + /* One more step to enable interrupt assist */ + set_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags); + /* Only open one port for I/O and interrupt emulation */ + if (v == d->vcpu[0]) { + memset(&d->shared_info->evtchn_mask[0], 0xff, + sizeof(d->shared_info->evtchn_mask)); + clear_bit(iopacket_port(d), &d->shared_info->evtchn_mask[0]); + } + + /* FIXME: only support PMT table continuously by far */ + d->arch.pmt = __va(c->pt_base); + d->arch.max_pfn = c->pt_max_pfn; + + vmx_final_setup_domain(d); +} + +typedef union { + u64 value; + struct { + u64 number : 8; + u64 revision : 8; + u64 model : 8; + u64 family : 8; + u64 archrev : 8; + u64 rv : 24; + }; +} cpuid3_t; + +/* Allocate vpd from xenheap */ +static vpd_t *alloc_vpd(void) +{ + int i; + cpuid3_t cpuid3; + vpd_t *vpd; + + vpd = alloc_xenheap_pages(get_order(VPD_SIZE)); + if (!vpd) { + printk("VPD allocation failed.\n"); + return NULL; + } + + printk("vpd base: 0x%lx, vpd size:%d\n", vpd, sizeof(vpd_t)); + memset(vpd, 0, VPD_SIZE); + /* CPUID init */ + for (i = 0; i < 5; i++) + vpd->vcpuid[i] = ia64_get_cpuid(i); + + /* Limit the CPUID number to 5 */ + cpuid3.value = vpd->vcpuid[3]; + cpuid3.number = 4; /* 5 - 1 */ + vpd->vcpuid[3] = cpuid3.value; + + vpd->vdc.d_vmsw = 1; + return vpd; +} + + +#ifdef CONFIG_VTI +/* + * Create a VP on intialized VMX environment. + */ +static void +vmx_create_vp(struct vcpu *v) +{ + u64 ret; + vpd_t *vpd = v->arch.arch_vmx.vpd; + u64 ivt_base; + extern char vmx_ia64_ivt; + /* ia64_ivt is function pointer, so need this tranlation */ + ivt_base = (u64) &vmx_ia64_ivt; + printk("ivt_base: 0x%lx\n", ivt_base); + ret = ia64_pal_vp_create(vpd, ivt_base, 0); + if (ret != PAL_STATUS_SUCCESS) + panic("ia64_pal_vp_create failed. \n"); +} + +#ifdef XEN_DBL_MAPPING +void vmx_init_double_mapping_stub(void) +{ + u64 base, psr; + extern void vmx_switch_rr7(void); + + base = (u64) &vmx_switch_rr7; + base = *((u64*)base); + + psr = ia64_clear_ic(); + ia64_itr(0x1, IA64_TR_RR7_SWITCH_STUB, XEN_RR7_SWITCH_STUB, + pte_val(pfn_pte(__pa(base) >> PAGE_SHIFT, PAGE_KERNEL)), + RR7_SWITCH_SHIFT); + ia64_set_psr(psr); + ia64_srlz_i(); + printk("Add TR mapping for rr7 switch stub, with physical: 0x%lx\n", (u64)(__pa(base))); +} +#endif + +/* Other non-context related tasks can be done in context switch */ +void +vmx_save_state(struct vcpu *v) +{ + u64 status, psr; + u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; + + /* FIXME: about setting of pal_proc_vector... time consuming */ + status = ia64_pal_vp_save(v->arch.arch_vmx.vpd, 0); + if (status != PAL_STATUS_SUCCESS) + panic("Save vp status failed\n"); + +#ifdef XEN_DBL_MAPPING + /* FIXME: Do we really need purge double mapping for old vcpu? + * Since rid is completely different between prev and next, + * it's not overlap and thus no MCA possible... */ + dom_rr7 = vmx_vrrtomrr(v, VMX(v, vrr[7])); + vmx_purge_double_mapping(dom_rr7, KERNEL_START, + (u64)v->arch.vtlb->ts->vhpt->hash); +#endif + + /* Need to save KR when domain switch, though HV itself doesn;t + * use them. + */ + v->arch.arch_vmx.vkr[0] = ia64_get_kr(0); + v->arch.arch_vmx.vkr[1] = ia64_get_kr(1); + v->arch.arch_vmx.vkr[2] = ia64_get_kr(2); + v->arch.arch_vmx.vkr[3] = ia64_get_kr(3); + v->arch.arch_vmx.vkr[4] = ia64_get_kr(4); + v->arch.arch_vmx.vkr[5] = ia64_get_kr(5); + v->arch.arch_vmx.vkr[6] = ia64_get_kr(6); + v->arch.arch_vmx.vkr[7] = ia64_get_kr(7); +} + +/* Even guest is in physical mode, we still need such double mapping */ +void +vmx_load_state(struct vcpu *v) +{ + u64 status, psr; + u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; + u64 pte_xen, pte_vhpt; + int i; + + status = ia64_pal_vp_restore(v->arch.arch_vmx.vpd, 0); + if (status != PAL_STATUS_SUCCESS) + panic("Restore vp status failed\n"); + +#ifdef XEN_DBL_MAPPING + dom_rr7 = vmx_vrrtomrr(v, VMX(v, vrr[7])); + pte_xen = pte_val(pfn_pte((xen_pstart >> PAGE_SHIFT), PAGE_KERNEL)); + pte_vhpt = pte_val(pfn_pte((__pa(v->arch.vtlb->ts->vhpt->hash) >> PAGE_SHIFT), PAGE_KERNEL)); + vmx_insert_double_mapping(dom_rr7, KERNEL_START, + (u64)v->arch.vtlb->ts->vhpt->hash, + pte_xen, pte_vhpt); +#endif + + ia64_set_kr(0, v->arch.arch_vmx.vkr[0]); + ia64_set_kr(1, v->arch.arch_vmx.vkr[1]); + ia64_set_kr(2, v->arch.arch_vmx.vkr[2]); + ia64_set_kr(3, v->arch.arch_vmx.vkr[3]); + ia64_set_kr(4, v->arch.arch_vmx.vkr[4]); + ia64_set_kr(5, v->arch.arch_vmx.vkr[5]); + ia64_set_kr(6, v->arch.arch_vmx.vkr[6]); + ia64_set_kr(7, v->arch.arch_vmx.vkr[7]); + /* Guest vTLB is not required to be switched explicitly, since + * anchored in vcpu */ +} + +#ifdef XEN_DBL_MAPPING +/* Purge old double mapping and insert new one, due to rr7 change */ +void +vmx_change_double_mapping(struct vcpu *v, u64 oldrr7, u64 newrr7) +{ + u64 pte_xen, pte_vhpt, vhpt_base; + + vhpt_base = (u64)v->arch.vtlb->ts->vhpt->hash; + vmx_purge_double_mapping(oldrr7, KERNEL_START, + vhpt_base); + + pte_xen = pte_val(pfn_pte((xen_pstart >> PAGE_SHIFT), PAGE_KERNEL)); + pte_vhpt = pte_val(pfn_pte((__pa(vhpt_base) >> PAGE_SHIFT), PAGE_KERNEL)); + vmx_insert_double_mapping(newrr7, KERNEL_START, + vhpt_base, + pte_xen, pte_vhpt); +} +#endif // XEN_DBL_MAPPING +#endif // CONFIG_VTI + +/* + * Initialize VMX envirenment for guest. Only the 1st vp/vcpu + * is registered here. + */ +void +vmx_final_setup_domain(struct domain *d) +{ + struct vcpu *v = d->vcpu[0]; + vpd_t *vpd; + + /* Allocate resources for vcpu 0 */ + //memset(&v->arch.arch_vmx, 0, sizeof(struct arch_vmx_struct)); + + vpd = alloc_vpd(); + ASSERT(vpd); + + v->arch.arch_vmx.vpd = vpd; + vpd->virt_env_vaddr = vm_buffer; + +#ifdef CONFIG_VTI + /* v->arch.schedule_tail = arch_vmx_do_launch; */ + vmx_create_vp(v); + + /* Set this ed to be vmx */ + set_bit(ARCH_VMX_VMCS_LOADED, &v->arch.arch_vmx.flags); + + /* Physical mode emulation initialization, including + * emulation ID allcation and related memory request + */ + physical_mode_init(v); + + vlsapic_reset(v); + vtm_init(v); +#endif + + /* Other vmx specific initialization work */ +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_interrupt.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_interrupt.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,388 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_interrupt.c: handle inject interruption. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> + * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + + +#include <xen/types.h> +#include <asm/vmx_vcpu.h> +#include <asm/vmx_mm_def.h> +#include <asm/vmx_pal_vsa.h> +/* SDM vol2 5.5 - IVA based interruption handling */ +#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 +void +collect_interruption(VCPU *vcpu) +{ + u64 ipsr; + u64 vdcr; + u64 vifs; + IA64_PSR vpsr; + REGS * regs = vcpu_regs(vcpu); + vpsr.val = vmx_vcpu_get_psr(vcpu); + + if(vpsr.ic){ + extern void vmx_dorfirfi(void); + if (regs->cr_iip == *(unsigned long *)vmx_dorfirfi) + panic("COLLECT interruption for vmx_dorfirfi\n"); + + /* Sync mpsr id/da/dd/ss/ed bits to vipsr + * since after guest do rfi, we still want these bits on in + * mpsr + */ + + ipsr = regs->cr_ipsr; + vpsr.val = vpsr.val | (ipsr & (IA64_PSR_ID | IA64_PSR_DA + | IA64_PSR_DD |IA64_PSR_SS |IA64_PSR_ED)); + vmx_vcpu_set_ipsr(vcpu, vpsr.val); + + /* Currently, for trap, we do not advance IIP to next + * instruction. That's because we assume caller already + * set up IIP correctly + */ + + vmx_vcpu_set_iip(vcpu , regs->cr_iip); + + /* set vifs.v to zero */ + vifs = VPD_CR(vcpu,ifs); + vifs &= ~IA64_IFS_V; + vmx_vcpu_set_ifs(vcpu, vifs); + + vmx_vcpu_set_iipa(vcpu, regs->cr_iipa); + } + + vdcr = VPD_CR(vcpu,dcr); + + /* Set guest psr + * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged + * be: set to the value of dcr.be + * pp: set to the value of dcr.pp + */ + vpsr.val &= INITIAL_PSR_VALUE_AT_INTERRUPTION; + vpsr.val |= ( vdcr & IA64_DCR_BE); + + /* VDCR pp bit position is different from VPSR pp bit */ + if ( vdcr & IA64_DCR_PP ) { + vpsr.val |= IA64_PSR_PP; + } else { + vpsr.val &= ~IA64_PSR_PP;; + } + + vmx_vcpu_set_psr(vcpu, vpsr.val); + +} +int +inject_guest_interruption(VCPU *vcpu, u64 vec) +{ + u64 viva; + REGS *regs; + regs=vcpu_regs(vcpu); + + collect_interruption(vcpu); + + vmx_vcpu_get_iva(vcpu,&viva); + regs->cr_iip = viva + vec; +} + + +/* + * Set vIFA & vITIR & vIHA, when vPSR.ic =1 + * Parameter: + * set_ifa: if true, set vIFA + * set_itir: if true, set vITIR + * set_iha: if true, set vIHA + */ +void +set_ifa_itir_iha (VCPU *vcpu, u64 vadr, + int set_ifa, int set_itir, int set_iha) +{ + IA64_PSR vpsr; + u64 value; + vpsr.val = vmx_vcpu_get_psr(vcpu); + /* Vol2, Table 8-1 */ + if ( vpsr.ic ) { + if ( set_ifa){ + vmx_vcpu_set_ifa(vcpu, vadr); + } + if ( set_itir) { + value = vmx_vcpu_get_itir_on_fault(vcpu, vadr); + vmx_vcpu_set_itir(vcpu, value); + } + + if ( set_iha) { + vmx_vcpu_thash(vcpu, vadr, &value); + vmx_vcpu_set_iha(vcpu, value); + } + } + + +} + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +dtlb_fault (VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu,IA64_DATA_TLB_VECTOR); +} + +/* + * Instruction TLB Fault + * @ Instruction TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +itlb_fault (VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu,IA64_INST_TLB_VECTOR); +} + + + +/* + * Data Nested TLB Fault + * @ Data Nested TLB Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +nested_dtlb (VCPU *vcpu) +{ + inject_guest_interruption(vcpu,IA64_DATA_NESTED_TLB_VECTOR); +} + +/* + * Alternate Data TLB Fault + * @ Alternate Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +alt_dtlb (VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha (vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu,IA64_ALT_DATA_TLB_VECTOR); +} + + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +alt_itlb (VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha (vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu,IA64_ALT_INST_TLB_VECTOR); +} + +/* Deal with: + * VHPT Translation Vector + */ +static void +_vhpt_fault(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA*/ + set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu,IA64_VHPT_TRANS_VECTOR); + + +} + +/* + * VHPT Instruction Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +ivhpt_fault (VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + +/* + * VHPT Data Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +dvhpt_fault (VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + + +/* + * Deal with: + * General Exception vector + */ +void +_general_exception (VCPU *vcpu) +{ + inject_guest_interruption(vcpu,IA64_GENEX_VECTOR); +} + + +/* + * Illegal Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +illegal_op (VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Illegal Dependency Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +illegal_dep (VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Reserved Register/Field Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +rsv_reg_field (VCPU *vcpu) +{ + _general_exception(vcpu); +} +/* + * Privileged Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ + +void +privilege_op (VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Unimplement Data Address Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +unimpl_daddr (VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Privileged Register Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +privilege_reg (VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* Deal with + * Nat consumption vector + * Parameter: + * vaddr: Optional, if t == REGISTER + */ +static void +_nat_consumption_fault(VCPU *vcpu, u64 vadr, miss_type t) +{ + /* If vPSR.ic && t == DATA/INST, IFA */ + if ( t == DATA || t == INSTRUCTION ) { + /* IFA */ + set_ifa_itir_iha (vcpu, vadr, 1, 0, 0); + } + + inject_guest_interruption(vcpu,IA64_NAT_CONSUMPTION_VECTOR); +} + +/* + * IR Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +static void +ir_nat_page_consumption (VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} + +/* + * Instruction Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +inat_page_consumption (VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, INSTRUCTION); +} + +/* + * Register Nat Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +rnat_consumption (VCPU *vcpu) +{ + _nat_consumption_fault(vcpu, 0, REGISTER); +} + +/* + * Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void +dnat_page_consumption (VCPU *vcpu, uint64_t vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} + +/* Deal with + * Page not present vector + */ +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); +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_irq_ia64.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_irq_ia64.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,127 @@ +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/jiffies.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel_stat.h> +#include <linux/slab.h> +#include <linux/ptrace.h> +#include <linux/random.h> /* for rand_initialize_irq() */ +#include <linux/signal.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/threads.h> +#include <linux/bitops.h> + +#include <asm/delay.h> +#include <asm/intrinsics.h> +#include <asm/io.h> +#include <asm/hw_irq.h> +#include <asm/machvec.h> +#include <asm/pgtable.h> +#include <asm/system.h> + +#ifdef CONFIG_PERFMON +# include <asm/perfmon.h> +#endif + +#define IRQ_DEBUG 0 + +#ifdef CONFIG_VTI +#define vmx_irq_enter() \ + add_preempt_count(HARDIRQ_OFFSET); + +/* Now softirq will be checked when leaving hypervisor, or else + * scheduler irq will be executed too early. + */ +#define vmx_irq_exit(void) \ + sub_preempt_count(HARDIRQ_OFFSET); +/* + * That's where the IVT branches when we get an external + * interrupt. This branches to the correct hardware IRQ handler via + * function ptr. + */ +void +vmx_ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) +{ + unsigned long saved_tpr; + int wake_dom0 = 0; + + +#if IRQ_DEBUG + { + unsigned long bsp, sp; + + /* + * Note: if the interrupt happened while executing in + * the context switch routine (ia64_switch_to), we may + * get a spurious stack overflow here. This is + * because the register and the memory stack are not + * switched atomically. + */ + bsp = ia64_getreg(_IA64_REG_AR_BSP); + sp = ia64_getreg(_IA64_REG_AR_SP); + + if ((sp - bsp) < 1024) { + static unsigned char count; + static long last_time; + + if (jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + printk("ia64_handle_irq: DANGER: less than " + "1KB of free stack space!!\n" + "(bsp=0x%lx, sp=%lx)\n", bsp, sp); + } + } + } +#endif /* IRQ_DEBUG */ + + /* + * Always set TPR to limit maximum interrupt nesting depth to + * 16 (without this, it would be ~240, which could easily lead + * to kernel stack overflows). + */ + vmx_irq_enter(); + saved_tpr = ia64_getreg(_IA64_REG_CR_TPR); + ia64_srlz_d(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + if (!IS_RESCHEDULE(vector)) { + ia64_setreg(_IA64_REG_CR_TPR, vector); + ia64_srlz_d(); + + if (vector != IA64_TIMER_VECTOR) { + /* FIXME: Leave IRQ re-route later */ + vmx_vcpu_pend_interrupt(dom0->vcpu[0],vector); + wake_dom0 = 1; + } + else { // FIXME: Handle Timer only now + __do_IRQ(local_vector_to_irq(vector), regs); + } + + /* + * Disable interrupts and send EOI: + */ + local_irq_disable(); + ia64_setreg(_IA64_REG_CR_TPR, saved_tpr); + } + else { + printf("Oops: RESCHEDULE IPI absorbed by HV\n"); + } + ia64_eoi(); + vector = ia64_get_ivr(); + } + /* + * This must be done *after* the ia64_eoi(). For example, the keyboard softirq + * handler needs to be able to wait for further keyboard interrupts, which can't + * come through until ia64_eoi() has been done. + */ + vmx_irq_exit(); + if ( wake_dom0 && current != dom0 ) + vcpu_wake(dom0->vcpu[0]); +} +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_ivt.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_ivt.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1085 @@ +/* + * arch/ia64/kernel/vmx_ivt.S + * + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co + * Stephane Eranian <eranian@xxxxxxxxxx> + * David Mosberger <davidm@xxxxxxxxxx> + * Copyright (C) 2000, 2002-2003 Intel Co + * Asit Mallick <asit.k.mallick@xxxxxxxxx> + * Suresh Siddha <suresh.b.siddha@xxxxxxxxx> + * Kenneth Chen <kenneth.w.chen@xxxxxxxxx> + * Fenghua Yu <fenghua.yu@xxxxxxxxx> + * + * + * 00/08/23 Asit Mallick <asit.k.mallick@xxxxxxxxx> TLB handling for SMP + * 00/12/20 David Mosberger-Tang <davidm@xxxxxxxxxx> DTLB/ITLB handler now uses virtual PT. + * + * 05/3/20 Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) + * Supporting Intel virtualization architecture + * + */ + +/* + * This file defines the interruption vector table used by the CPU. + * It does not include one entry per possible cause of interruption. + * + * The first 20 entries of the table contain 64 bundles each while the + * remaining 48 entries contain only 16 bundles each. + * + * The 64 bundles are used to allow inlining the whole handler for critical + * interruptions like TLB misses. + * + * For each entry, the comment is as follows: + * + * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + * entry offset ----/ / / / / + * entry number ---------/ / / / + * size of the entry -------------/ / / + * vector name -------------------------------------/ / + * interruptions triggering this vector ----------------------/ + * + * The table is 32KB in size and must be aligned on 32KB boundary. + * (The CPU ignores the 15 lower bits of the address) + * + * Table is based upon EAS2.6 (Oct 1999) + */ + +#include <linux/config.h> + +#include <asm/asmmacro.h> +#include <asm/break.h> +#include <asm/ia32.h> +#include <asm/kregs.h> +#include <asm/offsets.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/thread_info.h> +#include <asm/unistd.h> +#include <asm/vhpt.h> + + +#if 0 + /* + * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't + * needed for something else before enabling this... + */ +# define VMX_DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 +#else +# define VMX_DBG_FAULT(i) +#endif + +#include "vmx_minstate.h" + + + +#define VMX_FAULT(n) \ +vmx_fault_##n:; \ + br.sptk vmx_fault_##n; \ + ;; \ + + +#define VMX_REFLECT(n) \ + mov r31=pr; \ + mov r19=n; /* prepare to save predicates */ \ + mov r29=cr.ipsr; \ + ;; \ + tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \ +(p7) br.sptk.many vmx_dispatch_reflection; \ + VMX_FAULT(n); \ + + +GLOBAL_ENTRY(vmx_panic) + br.sptk.many vmx_panic + ;; +END(vmx_panic) + + + + + + .section .text.ivt,"ax" + + .align 32768 // align on 32KB boundary + .global vmx_ia64_ivt +vmx_ia64_ivt: +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) +ENTRY(vmx_vhpt_miss) + VMX_FAULT(0) +END(vmx_vhpt_miss) + + .org vmx_ia64_ivt+0x400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0400 Entry 1 (size 64 bundles) ITLB (21) +ENTRY(vmx_itlb_miss) + mov r31 = pr + mov r29=cr.ipsr; + ;; + tbit.z p6,p7=r29,IA64_PSR_VM_BIT; +(p6) br.sptk vmx_fault_1 + mov r16 = cr.ifa + ;; + thash r17 = r16 + ttag r20 = r16 + ;; +vmx_itlb_loop: + cmp.eq p6,p0 = r0, r17 +(p6) br vmx_itlb_out + ;; + adds r22 = VLE_TITAG_OFFSET, r17 + adds r23 = VLE_CCHAIN_OFFSET, r17 + ;; + ld8 r24 = [r22] + ld8 r25 = [r23] + ;; + lfetch [r25] + cmp.eq p6,p7 = r20, r24 + ;; +(p7) mov r17 = r25; +(p7) br.sptk vmx_itlb_loop + ;; + adds r23 = VLE_PGFLAGS_OFFSET, r17 + adds r24 = VLE_ITIR_OFFSET, r17 + ;; + ld8 r26 = [r23] + ld8 r25 = [r24] + ;; + mov cr.itir = r25 + ;; + itc.i r26 + ;; + srlz.i + ;; + mov r23=r31 + mov r22=b0 + adds r16=IA64_VPD_BASE_OFFSET,r21 + ;; + ld8 r18=[r16] + ;; + adds r19=VPD(VPSR),r18 + movl r20=__vsa_base + ;; + ld8 r19=[r19] + ld8 r20=[r20] + ;; + br.sptk ia64_vmm_entry + ;; +vmx_itlb_out: + mov r19 = 1 + br.sptk vmx_dispatch_tlb_miss + VMX_FAULT(1); +END(vmx_itlb_miss) + + .org vmx_ia64_ivt+0x0800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) +ENTRY(vmx_dtlb_miss) + mov r31 = pr + mov r29=cr.ipsr; + ;; + tbit.z p6,p7=r29,IA64_PSR_VM_BIT; +(p6)br.sptk vmx_fault_2 + mov r16 = cr.ifa + ;; + thash r17 = r16 + ttag r20 = r16 + ;; +vmx_dtlb_loop: + cmp.eq p6,p0 = r0, r17 +(p6)br vmx_dtlb_out + ;; + adds r22 = VLE_TITAG_OFFSET, r17 + adds r23 = VLE_CCHAIN_OFFSET, r17 + ;; + ld8 r24 = [r22] + ld8 r25 = [r23] + ;; + lfetch [r25] + cmp.eq p6,p7 = r20, r24 + ;; +(p7)mov r17 = r25; +(p7)br.sptk vmx_dtlb_loop + ;; + adds r23 = VLE_PGFLAGS_OFFSET, r17 + adds r24 = VLE_ITIR_OFFSET, r17 + ;; + ld8 r26 = [r23] + ld8 r25 = [r24] + ;; + mov cr.itir = r25 + ;; + itc.d r26 + ;; + srlz.d; + ;; + mov r23=r31 + mov r22=b0 + adds r16=IA64_VPD_BASE_OFFSET,r21 + ;; + ld8 r18=[r16] + ;; + adds r19=VPD(VPSR),r18 + movl r20=__vsa_base + ;; + ld8 r19=[r19] + ld8 r20=[r20] + ;; + br.sptk ia64_vmm_entry + ;; +vmx_dtlb_out: + mov r19 = 2 + br.sptk vmx_dispatch_tlb_miss + VMX_FAULT(2); +END(vmx_dtlb_miss) + + .org vmx_ia64_ivt+0x0c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) +ENTRY(vmx_alt_itlb_miss) + mov r31 = pr + mov r29=cr.ipsr; + ;; + tbit.z p6,p7=r29,IA64_PSR_VM_BIT; +(p7)br.sptk vmx_fault_3 + mov r16=cr.ifa // get address that caused the TLB miss + movl r17=PAGE_KERNEL + mov r24=cr.ipsr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + ;; + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits + shr.u r18=r16,55 // move address bit 59 to bit 4 + ;; + and r18=0x10,r18 // bit 4=address-bit(61) + or r19=r17,r19 // insert PTE control bits into r19 + ;; + or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 + ;; + itc.i r19 // insert the TLB entry + mov pr=r31,-1 + rfi + VMX_FAULT(3); +END(vmx_alt_itlb_miss) + + + .org vmx_ia64_ivt+0x1000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) +ENTRY(vmx_alt_dtlb_miss) + mov r31=pr + mov r29=cr.ipsr; + ;; + tbit.z p6,p7=r29,IA64_PSR_VM_BIT; +(p7)br.sptk vmx_fault_4 + mov r16=cr.ifa // get address that caused the TLB miss + movl r17=PAGE_KERNEL + mov r20=cr.isr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + mov r24=cr.ipsr + ;; + and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field + tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? + shr.u r18=r16,55 // move address bit 59 to bit 4 + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits + tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? + ;; + and r18=0x10,r18 // bit 4=address-bit(61) +(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field + dep r24=-1,r24,IA64_PSR_ED_BIT,1 + or r19=r19,r17 // insert PTE control bits into r19 + ;; + or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 +(p6) mov cr.ipsr=r24 + ;; +(p7) itc.d r19 // insert the TLB entry + mov pr=r31,-1 + rfi + VMX_FAULT(4); +END(vmx_alt_dtlb_miss) + + .org vmx_ia64_ivt+0x1400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) +ENTRY(vmx_nested_dtlb_miss) + VMX_FAULT(5) +END(vmx_nested_dtlb_miss) + + .org vmx_ia64_ivt+0x1800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) +ENTRY(vmx_ikey_miss) + VMX_REFLECT(6) +END(vmx_ikey_miss) + + .org vmx_ia64_ivt+0x1c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) +ENTRY(vmx_dkey_miss) + VMX_REFLECT(7) +END(vmx_dkey_miss) + + .org vmx_ia64_ivt+0x2000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) +ENTRY(vmx_dirty_bit) + VMX_REFLECT(8) +END(vmx_idirty_bit) + + .org vmx_ia64_ivt+0x2400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) +ENTRY(vmx_iaccess_bit) + VMX_REFLECT(9) +END(vmx_iaccess_bit) + + .org vmx_ia64_ivt+0x2800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) +ENTRY(vmx_daccess_bit) + VMX_REFLECT(10) +END(vmx_daccess_bit) + + .org vmx_ia64_ivt+0x2c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) +ENTRY(vmx_break_fault) + mov r31=pr + mov r19=11 + mov r30=cr.iim + movl r29=0x1100 + ;; + cmp.eq p6,p7=r30,r0 + (p6) br.sptk vmx_fault_11 + ;; + cmp.eq p6,p7=r29,r30 + (p6) br.dptk.few vmx_hypercall_dispatch + (p7) br.sptk.many vmx_dispatch_break_fault + ;; + VMX_FAULT(11); +END(vmx_break_fault) + + .org vmx_ia64_ivt+0x3000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) +ENTRY(vmx_interrupt) + mov r31=pr // prepare to save predicates + mov r19=12 + mov r29=cr.ipsr + ;; + tbit.z p6,p7=r29,IA64_PSR_VM_BIT + tbit.z p0,p15=r29,IA64_PSR_I_BIT + ;; +(p7) br.sptk vmx_dispatch_interrupt + ;; + mov r27=ar.rsc /* M */ + mov r20=r1 /* A */ + mov r25=ar.unat /* M */ + mov r26=ar.pfs /* I */ + mov r28=cr.iip /* M */ + cover /* B (or nothing) */ + ;; + mov r1=sp + ;; + invala /* M */ + mov r30=cr.ifs + ;; + addl r1=-IA64_PT_REGS_SIZE,r1 + ;; + adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line size */ + adds r16=PT(CR_IPSR),r1 + ;; + lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES + st8 [r16]=r29 /* save cr.ipsr */ + ;; + lfetch.fault.excl.nt1 [r17] + mov r29=b0 + ;; + adds r16=PT(R8),r1 /* initialize first base pointer */ + adds r17=PT(R9),r1 /* initialize second base pointer */ + mov r18=r0 /* make sure r18 isn't NaT */ + ;; +.mem.offset 0,0; st8.spill [r16]=r8,16 +.mem.offset 8,0; st8.spill [r17]=r9,16 + ;; +.mem.offset 0,0; st8.spill [r16]=r10,24 +.mem.offset 8,0; st8.spill [r17]=r11,24 + ;; + st8 [r16]=r28,16 /* save cr.iip */ + st8 [r17]=r30,16 /* save cr.ifs */ + mov r8=ar.fpsr /* M */ + mov r9=ar.csd + mov r10=ar.ssd + movl r11=FPSR_DEFAULT /* L-unit */ + ;; + st8 [r16]=r25,16 /* save ar.unat */ + st8 [r17]=r26,16 /* save ar.pfs */ + shl r18=r18,16 /* compute ar.rsc to be used for "loadrs" */ + ;; + st8 [r16]=r27,16 /* save ar.rsc */ + adds r17=16,r17 /* skip over ar_rnat field */ + ;; /* avoid RAW on r16 & r17 */ + st8 [r17]=r31,16 /* save predicates */ + adds r16=16,r16 /* skip over ar_bspstore field */ + ;; + st8 [r16]=r29,16 /* save b0 */ + st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */ + ;; +.mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */ +.mem.offset 8,0; st8.spill [r17]=r12,16 + adds r12=-16,r1 /* switch to kernel memory stack (with 16 bytes of scratch) */ + ;; +.mem.offset 0,0; st8.spill [r16]=r13,16 +.mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */ + mov r13=r21 /* establish `current' */ + ;; +.mem.offset 0,0; st8.spill [r16]=r15,16 +.mem.offset 8,0; st8.spill [r17]=r14,16 + dep r14=-1,r0,60,4 + ;; +.mem.offset 0,0; st8.spill [r16]=r2,16 +.mem.offset 8,0; st8.spill [r17]=r3,16 + adds r2=IA64_PT_REGS_R16_OFFSET,r1 + ;; + mov r8=ar.ccv + movl r1=__gp /* establish kernel global pointer */ + ;; \ + bsw.1 + ;; + alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group + mov out0=cr.ivr // pass cr.ivr as first arg + add out1=16,sp // pass pointer to pt_regs as second arg + + ssm psr.ic + ;; + srlz.i + ;; + (p15) ssm psr.i + adds r3=8,r2 // set up second base pointer for SAVE_REST + srlz.i // ensure everybody knows psr.ic is back on + ;; +.mem.offset 0,0; st8.spill [r2]=r16,16 +.mem.offset 8,0; st8.spill [r3]=r17,16 + ;; +.mem.offset 0,0; st8.spill [r2]=r18,16 +.mem.offset 8,0; st8.spill [r3]=r19,16 + ;; +.mem.offset 0,0; st8.spill [r2]=r20,16 +.mem.offset 8,0; st8.spill [r3]=r21,16 + mov r18=b6 + ;; +.mem.offset 0,0; st8.spill [r2]=r22,16 +.mem.offset 8,0; st8.spill [r3]=r23,16 + mov r19=b7 + ;; +.mem.offset 0,0; st8.spill [r2]=r24,16 +.mem.offset 8,0; st8.spill [r3]=r25,16 + ;; +.mem.offset 0,0; st8.spill [r2]=r26,16 +.mem.offset 8,0; st8.spill [r3]=r27,16 + ;; +.mem.offset 0,0; st8.spill [r2]=r28,16 +.mem.offset 8,0; st8.spill [r3]=r29,16 + ;; +.mem.offset 0,0; st8.spill [r2]=r30,16 +.mem.offset 8,0; st8.spill [r3]=r31,32 + ;; + mov ar.fpsr=r11 /* M-unit */ + st8 [r2]=r8,8 /* ar.ccv */ + adds r24=PT(B6)-PT(F7),r3 + ;; + stf.spill [r2]=f6,32 + stf.spill [r3]=f7,32 + ;; + stf.spill [r2]=f8,32 + stf.spill [r3]=f9,32 + ;; + stf.spill [r2]=f10 + stf.spill [r3]=f11 + adds r25=PT(B7)-PT(F11),r3 + ;; + st8 [r24]=r18,16 /* b6 */ + st8 [r25]=r19,16 /* b7 */ + ;; + st8 [r24]=r9 /* ar.csd */ + st8 [r25]=r10 /* ar.ssd */ + ;; + srlz.d // make sure we see the effect of cr.ivr + movl r14=ia64_leave_nested + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_ia64_handle_irq + ;; +END(vmx_interrupt) + + .org vmx_ia64_ivt+0x3400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3400 Entry 13 (size 64 bundles) Reserved +ENTRY(vmx_virtual_exirq) + VMX_DBG_FAULT(13) + mov r31=pr + mov r19=13 + br.sptk vmx_dispatch_vexirq +END(vmx_virtual_exirq) + + .org vmx_ia64_ivt+0x3800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3800 Entry 14 (size 64 bundles) Reserved + VMX_DBG_FAULT(14) + VMX_FAULT(14) + + + .org vmx_ia64_ivt+0x3c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3c00 Entry 15 (size 64 bundles) Reserved + VMX_DBG_FAULT(15) + VMX_FAULT(15) + + + .org vmx_ia64_ivt+0x4000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4000 Entry 16 (size 64 bundles) Reserved + VMX_DBG_FAULT(16) + VMX_FAULT(16) + + .org vmx_ia64_ivt+0x4400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4400 Entry 17 (size 64 bundles) Reserved + VMX_DBG_FAULT(17) + VMX_FAULT(17) + + .org vmx_ia64_ivt+0x4800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4800 Entry 18 (size 64 bundles) Reserved + VMX_DBG_FAULT(18) + VMX_FAULT(18) + + .org vmx_ia64_ivt+0x4c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4c00 Entry 19 (size 64 bundles) Reserved + VMX_DBG_FAULT(19) + VMX_FAULT(19) + + .org vmx_ia64_ivt+0x5000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5000 Entry 20 (size 16 bundles) Page Not Present +ENTRY(vmx_page_not_present) + VMX_REFLECT(20) +END(vmx_page_not_present) + + .org vmx_ia64_ivt+0x5100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5100 Entry 21 (size 16 bundles) Key Permission vector +ENTRY(vmx_key_permission) + VMX_REFLECT(21) +END(vmx_key_permission) + + .org vmx_ia64_ivt+0x5200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) +ENTRY(vmx_iaccess_rights) + VMX_REFLECT(22) +END(vmx_iaccess_rights) + + .org vmx_ia64_ivt+0x5300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) +ENTRY(vmx_daccess_rights) + VMX_REFLECT(23) +END(vmx_daccess_rights) + + .org vmx_ia64_ivt+0x5400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) +ENTRY(vmx_general_exception) + VMX_FAULT(24) +// VMX_REFLECT(24) +END(vmx_general_exception) + + .org vmx_ia64_ivt+0x5500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) +ENTRY(vmx_disabled_fp_reg) + VMX_REFLECT(25) +END(vmx_disabled_fp_reg) + + .org vmx_ia64_ivt+0x5600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) +ENTRY(vmx_nat_consumption) + VMX_REFLECT(26) +END(vmx_nat_consumption) + + .org vmx_ia64_ivt+0x5700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5700 Entry 27 (size 16 bundles) Speculation (40) +ENTRY(vmx_speculation_vector) + VMX_REFLECT(27) +END(vmx_speculation_vector) + + .org vmx_ia64_ivt+0x5800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5800 Entry 28 (size 16 bundles) Reserved + VMX_DBG_FAULT(28) + VMX_FAULT(28) + + .org vmx_ia64_ivt+0x5900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) +ENTRY(vmx_debug_vector) + VMX_DBG_FAULT(29) + VMX_FAULT(29) +END(vmx_debug_vector) + + .org vmx_ia64_ivt+0x5a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) +ENTRY(vmx_unaligned_access) + VMX_REFLECT(30) +END(vmx_unaligned_access) + + .org vmx_ia64_ivt+0x5b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) +ENTRY(vmx_unsupported_data_reference) + VMX_REFLECT(31) +END(vmx_unsupported_data_reference) + + .org vmx_ia64_ivt+0x5c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) +ENTRY(vmx_floating_point_fault) + VMX_REFLECT(32) +END(vmx_floating_point_fault) + + .org vmx_ia64_ivt+0x5d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) +ENTRY(vmx_floating_point_trap) + VMX_REFLECT(33) +END(vmx_floating_point_trap) + + .org vmx_ia64_ivt+0x5e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) +ENTRY(vmx_lower_privilege_trap) + VMX_REFLECT(34) +END(vmx_lower_privilege_trap) + + .org vmx_ia64_ivt+0x5f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) +ENTRY(vmx_taken_branch_trap) + VMX_REFLECT(35) +END(vmx_taken_branch_trap) + + .org vmx_ia64_ivt+0x6000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) +ENTRY(vmx_single_step_trap) + VMX_REFLECT(36) +END(vmx_single_step_trap) + + .org vmx_ia64_ivt+0x6100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6100 Entry 37 (size 16 bundles) Virtualization Fault +ENTRY(vmx_virtualization_fault) + VMX_DBG_FAULT(37) + mov r31=pr + mov r19=37 + br.sptk vmx_dispatch_virtualization_fault +END(vmx_virtualization_fault) + + .org vmx_ia64_ivt+0x6200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6200 Entry 38 (size 16 bundles) Reserved + VMX_DBG_FAULT(38) + VMX_FAULT(38) + + .org vmx_ia64_ivt+0x6300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6300 Entry 39 (size 16 bundles) Reserved + VMX_DBG_FAULT(39) + VMX_FAULT(39) + + .org vmx_ia64_ivt+0x6400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6400 Entry 40 (size 16 bundles) Reserved + VMX_DBG_FAULT(40) + VMX_FAULT(40) + + .org vmx_ia64_ivt+0x6500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6500 Entry 41 (size 16 bundles) Reserved + VMX_DBG_FAULT(41) + VMX_FAULT(41) + + .org vmx_ia64_ivt+0x6600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6600 Entry 42 (size 16 bundles) Reserved + VMX_DBG_FAULT(42) + VMX_FAULT(42) + + .org vmx_ia64_ivt+0x6700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6700 Entry 43 (size 16 bundles) Reserved + VMX_DBG_FAULT(43) + VMX_FAULT(43) + + .org vmx_ia64_ivt+0x6800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6800 Entry 44 (size 16 bundles) Reserved + VMX_DBG_FAULT(44) + VMX_FAULT(44) + + .org vmx_ia64_ivt+0x6900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) +ENTRY(vmx_ia32_exception) + VMX_DBG_FAULT(45) + VMX_FAULT(45) +END(vmx_ia32_exception) + + .org vmx_ia64_ivt+0x6a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) +ENTRY(vmx_ia32_intercept) + VMX_DBG_FAULT(46) + VMX_FAULT(46) +END(vmx_ia32_intercept) + + .org vmx_ia64_ivt+0x6b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) +ENTRY(vmx_ia32_interrupt) + VMX_DBG_FAULT(47) + VMX_FAULT(47) +END(vmx_ia32_interrupt) + + .org vmx_ia64_ivt+0x6c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6c00 Entry 48 (size 16 bundles) Reserved + VMX_DBG_FAULT(48) + VMX_FAULT(48) + + .org vmx_ia64_ivt+0x6d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6d00 Entry 49 (size 16 bundles) Reserved + VMX_DBG_FAULT(49) + VMX_FAULT(49) + + .org vmx_ia64_ivt+0x6e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6e00 Entry 50 (size 16 bundles) Reserved + VMX_DBG_FAULT(50) + VMX_FAULT(50) + + .org vmx_ia64_ivt+0x6f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6f00 Entry 51 (size 16 bundles) Reserved + VMX_DBG_FAULT(51) + VMX_FAULT(51) + + .org vmx_ia64_ivt+0x7000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7000 Entry 52 (size 16 bundles) Reserved + VMX_DBG_FAULT(52) + VMX_FAULT(52) + + .org vmx_ia64_ivt+0x7100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7100 Entry 53 (size 16 bundles) Reserved + VMX_DBG_FAULT(53) + VMX_FAULT(53) + + .org vmx_ia64_ivt+0x7200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7200 Entry 54 (size 16 bundles) Reserved + VMX_DBG_FAULT(54) + VMX_FAULT(54) + + .org vmx_ia64_ivt+0x7300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7300 Entry 55 (size 16 bundles) Reserved + VMX_DBG_FAULT(55) + VMX_FAULT(55) + + .org vmx_ia64_ivt+0x7400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7400 Entry 56 (size 16 bundles) Reserved + VMX_DBG_FAULT(56) + VMX_FAULT(56) + + .org vmx_ia64_ivt+0x7500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7500 Entry 57 (size 16 bundles) Reserved + VMX_DBG_FAULT(57) + VMX_FAULT(57) + + .org vmx_ia64_ivt+0x7600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7600 Entry 58 (size 16 bundles) Reserved + VMX_DBG_FAULT(58) + VMX_FAULT(58) + + .org vmx_ia64_ivt+0x7700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7700 Entry 59 (size 16 bundles) Reserved + VMX_DBG_FAULT(59) + VMX_FAULT(59) + + .org vmx_ia64_ivt+0x7800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7800 Entry 60 (size 16 bundles) Reserved + VMX_DBG_FAULT(60) + VMX_FAULT(60) + + .org vmx_ia64_ivt+0x7900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7900 Entry 61 (size 16 bundles) Reserved + VMX_DBG_FAULT(61) + VMX_FAULT(61) + + .org vmx_ia64_ivt+0x7a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7a00 Entry 62 (size 16 bundles) Reserved + VMX_DBG_FAULT(62) + VMX_FAULT(62) + + .org vmx_ia64_ivt+0x7b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7b00 Entry 63 (size 16 bundles) Reserved + VMX_DBG_FAULT(63) + VMX_FAULT(63) + + .org vmx_ia64_ivt+0x7c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7c00 Entry 64 (size 16 bundles) Reserved + VMX_DBG_FAULT(64) + VMX_FAULT(64) + + .org vmx_ia64_ivt+0x7d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7d00 Entry 65 (size 16 bundles) Reserved + VMX_DBG_FAULT(65) + VMX_FAULT(65) + + .org vmx_ia64_ivt+0x7e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7e00 Entry 66 (size 16 bundles) Reserved + VMX_DBG_FAULT(66) + VMX_FAULT(66) + + .org vmx_ia64_ivt+0x7f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7f00 Entry 67 (size 16 bundles) Reserved + VMX_DBG_FAULT(67) + VMX_FAULT(67) + + .org vmx_ia64_ivt+0x8000 + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + + +ENTRY(vmx_dispatch_reflection) + /* + * Input: + * psr.ic: off + * r19: intr type (offset into ivt, see ia64_int.h) + * r31: contains saved predicates (pr) + */ + VMX_SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,4,0 + mov out0=cr.ifa + mov out1=cr.isr + mov out2=cr.iim + mov out3=r15 + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_reflect_interruption +END(vmx_dispatch_reflection) + +ENTRY(vmx_dispatch_virtualization_fault) + VMX_SAVE_MIN_WITH_COVER_R19 + ;; + alloc r14=ar.pfs,0,0,3,0 // now it's safe (must be first in insn group!) + mov out0=r13 //vcpu + mov out1=r4 //cause + mov out2=r5 //opcode + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_emulate +END(vmx_dispatch_virtualization_fault) + + +ENTRY(vmx_dispatch_vexirq) + VMX_SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,1,0 + mov out0=r13 + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_vexirq +END(vmx_dispatch_vexirq) + +ENTRY(vmx_dispatch_tlb_miss) + VMX_SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,3,0 + mov out0=r13 + mov out1=r15 + mov out2=cr.ifa + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_hpw_miss +END(vmx_dispatch_tlb_miss) + + +ENTRY(vmx_dispatch_break_fault) + VMX_SAVE_MIN_WITH_COVER_R19 + ;; + ;; + alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + mov out2=cr.isr // FIXME: pity to make this slow access twice + mov out3=cr.iim // FIXME: pity to make this slow access twice + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15)ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_ia64_handle_break + ;; +END(vmx_dispatch_break_fault) + + +ENTRY(vmx_hypercall_dispatch) + VMX_SAVE_MIN_WITH_COVER + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + ;; + movl r14=ia64_leave_hypervisor + movl r2=hyper_call_table + ;; + mov rp=r14 + shladd r2=r15,3,r2 + ;; + ld8 r2=[r2] + ;; + mov b6=r2 + ;; + br.call.sptk.many b6=b6 + ;; +END(vmx_hypercall_dispatch) + + + +ENTRY(vmx_dispatch_interrupt) + VMX_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3 + ;; + alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group + mov out0=cr.ivr // pass cr.ivr as first arg + add out1=16,sp // pass pointer to pt_regs as second arg + + ssm psr.ic + ;; + srlz.i + ;; + (p15) ssm psr.i + adds r3=16,r2 // set up second base pointer for SAVE_REST + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_ia64_handle_irq +END(vmx_dispatch_interrupt) + + + + .rodata + .align 8 + .globl hyper_call_table +hyper_call_table: + data8 hyper_not_support //hyper_set_trap_table /* 0 */ + data8 hyper_mmu_update + data8 hyper_not_support //hyper_set_gdt + data8 hyper_not_support //hyper_stack_switch + data8 hyper_not_support //hyper_set_callbacks + data8 hyper_not_support //hyper_fpu_taskswitch /* 5 */ + data8 hyper_sched_op + data8 hyper_dom0_op + data8 hyper_not_support //hyper_set_debugreg + data8 hyper_not_support //hyper_get_debugreg + data8 hyper_not_support //hyper_update_descriptor /* 10 */ + data8 hyper_not_support //hyper_set_fast_trap + data8 hyper_dom_mem_op + data8 hyper_not_support //hyper_multicall + data8 hyper_not_support //hyper_update_va_mapping + data8 hyper_not_support //hyper_set_timer_op /* 15 */ + data8 hyper_event_channel_op + data8 hyper_xen_version + data8 hyper_not_support //hyper_console_io + data8 hyper_not_support //hyper_physdev_op + data8 hyper_not_support //hyper_grant_table_op /* 20 */ + data8 hyper_not_support //hyper_vm_assist + data8 hyper_not_support //hyper_update_va_mapping_otherdomain + data8 hyper_not_support //hyper_switch_vm86 + data8 hyper_not_support //hyper_boot_vcpu + data8 hyper_not_support //hyper_ni_hypercall /* 25 */ + data8 hyper_not_support //hyper_mmuext_op + data8 hyper_lock_page + data8 hyper_set_shared_page diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_minstate.h --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_minstate.h Thu Sep 1 18:46:28 2005 @@ -0,0 +1,333 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_minstate.h: + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <linux/config.h> + +#include <asm/asmmacro.h> +#include <asm/fpu.h> +#include <asm/mmu_context.h> +#include <asm/offsets.h> +#include <asm/pal.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/vmx_pal_vsa.h> +#include <asm/vmx_vpd.h> +#include <asm/cache.h> +#include "entry.h" + +#define VMX_MINSTATE_START_SAVE_MIN \ + mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ + ;; \ + mov.m r28=ar.rnat; \ + addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ + ;; \ + lfetch.fault.excl.nt1 [r22]; \ + addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ + mov r23=ar.bspstore; /* save ar.bspstore */ \ + ;; \ + mov ar.bspstore=r22; /* switch to kernel RBS */ \ + ;; \ + mov r18=ar.bsp; \ + mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ + + + +#define VMX_MINSTATE_END_SAVE_MIN \ + bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ + ;; + + +#define PAL_VSA_SYNC_READ_CLEANUP_PSR_PL \ + /* begin to call pal vps sync_read and cleanup psr.pl */ \ + add r25=IA64_VPD_BASE_OFFSET, r21; \ + movl r20=__vsa_base; \ + ;; \ + ld8 r25=[r25]; /* read vpd base */ \ + ld8 r20=[r20]; /* read entry point */ \ + ;; \ + mov r6=r25; \ + add r20=PAL_VPS_SYNC_READ,r20; \ + ;; \ +{ .mii; \ + add r22=VPD(VPSR),r25; \ + mov r24=ip; \ + mov b0=r20; \ + ;; \ +}; \ +{ .mmb; \ + add r24 = 0x20, r24; \ + mov r16 = cr.ipsr; /* Temp workaround since psr.ic is off */ \ + br.cond.sptk b0; /* call the service */ \ + ;; \ +}; \ + ld8 r7=[r22]; \ + /* deposite ipsr bit cpl into vpd.vpsr, since epc will change */ \ + extr.u r30=r16, IA64_PSR_CPL0_BIT, 2; \ + ;; \ + dep r7=r30, r7, IA64_PSR_CPL0_BIT, 2; \ + ;; \ + extr.u r30=r16, IA64_PSR_BE_BIT, 5; \ + ;; \ + dep r7=r30, r7, IA64_PSR_BE_BIT, 5; \ + ;; \ + extr.u r30=r16, IA64_PSR_RI_BIT, 2; \ + ;; \ + dep r7=r30, r7, IA64_PSR_RI_BIT, 2; \ + ;; \ + st8 [r22]=r7; \ + ;; + + + +#define IA64_CURRENT_REG IA64_KR(CURRENT) /* r21 is reserved for current pointer */ +//#define VMX_MINSTATE_GET_CURRENT(reg) mov reg=IA64_CURRENT_REG +#define VMX_MINSTATE_GET_CURRENT(reg) mov reg=r21 + +/* + * VMX_DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves + * the minimum state necessary that allows us to turn psr.ic back + * on. + * + * Assumed state upon entry: + * psr.ic: off + * r31: contains saved predicates (pr) + * + * Upon exit, the state is as follows: + * psr.ic: off + * r2 = points to &pt_regs.r16 + * r8 = contents of ar.ccv + * r9 = contents of ar.csd + * r10 = contents of ar.ssd + * r11 = FPSR_DEFAULT + * r12 = kernel sp (kernel virtual address) + * r13 = points to current task_struct (kernel virtual address) + * p15 = TRUE if psr.i is set in cr.ipsr + * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: + * preserved + * + * Note that psr.ic is NOT turned on by this macro. This is so that + * we can pass interruption state as arguments to a handler. + */ +#define VMX_DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ +/* switch rr7 */ \ + movl r16=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)); \ + movl r17=(7<<61); \ + movl r20=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)); \ + movl r22=(6<<61); \ + movl r18=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1); \ + movl r23=(5<<61); \ + ;; \ + mov rr[r17]=r16; \ + mov rr[r22]=r20; \ + mov rr[r23]=r18; \ + ;; \ + srlz.i; \ + ;; \ + VMX_MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ + mov r27=ar.rsc; /* M */ \ + mov r20=r1; /* A */ \ + mov r26=ar.unat; /* M */ \ + mov r29=cr.ipsr; /* M */ \ + mov r18=cr.isr; \ + COVER; /* B;; (or nothing) */ \ + ;; \ + tbit.z p6,p0=r29,IA64_PSR_VM_BIT; \ + tbit.nz.or p6,p0 = r18,39; \ + ;; \ +(p6) br.sptk.few vmx_panic; \ + tbit.z p0,p15=r29,IA64_PSR_I_BIT; \ + mov r1=r16; \ +/* mov r21=r16; */ \ + /* switch from user to kernel RBS: */ \ + ;; \ + invala; /* M */ \ + SAVE_IFS; \ + ;; \ + VMX_MINSTATE_START_SAVE_MIN \ + adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ + adds r16=PT(CR_IPSR),r1; \ + ;; \ + lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ + st8 [r16]=r29; /* save cr.ipsr */ \ + ;; \ + lfetch.fault.excl.nt1 [r17]; \ + tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ + mov r29=b0 \ + ;; \ + adds r16=PT(R8),r1; /* initialize first base pointer */ \ + adds r17=PT(R9),r1; /* initialize second base pointer */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r8,16; \ +.mem.offset 8,0; st8.spill [r17]=r9,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r10,24; \ +.mem.offset 8,0; st8.spill [r17]=r11,24; \ + ;; \ + mov r8=ar.pfs; /* I */ \ + mov r9=cr.iip; /* M */ \ + mov r10=ar.fpsr; /* M */ \ + ;; \ + st8 [r16]=r9,16; /* save cr.iip */ \ + st8 [r17]=r30,16; /* save cr.ifs */ \ + sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ + ;; \ + st8 [r16]=r26,16; /* save ar.unat */ \ + st8 [r17]=r8,16; /* save ar.pfs */ \ + shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ + ;; \ + st8 [r16]=r27,16; /* save ar.rsc */ \ + st8 [r17]=r28,16; /* save ar.rnat */ \ + ;; /* avoid RAW on r16 & r17 */ \ + st8 [r16]=r23,16; /* save ar.bspstore */ \ + st8 [r17]=r31,16; /* save predicates */ \ + ;; \ + st8 [r16]=r29,16; /* save b0 */ \ + st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ +.mem.offset 8,0; st8.spill [r17]=r12,16; \ + adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r13,16; \ +.mem.offset 8,0; st8.spill [r17]=r10,16; /* save ar.fpsr */ \ + mov r13=r21; /* establish `current' */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r15,16; \ +.mem.offset 8,0; st8.spill [r17]=r14,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r2,16; \ +.mem.offset 8,0; st8.spill [r17]=r3,16; \ + adds r2=PT(F6),r1; \ + ;; \ + .mem.offset 0,0; st8.spill [r16]=r4,16; \ + .mem.offset 8,0; st8.spill [r17]=r5,16; \ + ;; \ + .mem.offset 0,0; st8.spill [r16]=r6,16; \ + .mem.offset 8,0; st8.spill [r17]=r7,16; \ + mov r20=ar.ccv; \ + ;; \ + mov r18=cr.iipa; \ + mov r4=cr.isr; \ + mov r22=ar.unat; \ + ;; \ + st8 [r16]=r18,16; \ + st8 [r17]=r4; \ + ;; \ + adds r16=PT(EML_UNAT),r1; \ + adds r17=PT(AR_CCV),r1; \ + ;; \ + st8 [r16]=r22,8; \ + st8 [r17]=r20; \ + mov r4=r24; \ + mov r5=r25; \ + ;; \ + st8 [r16]=r0; \ + EXTRA; \ + mov r9=ar.csd; \ + mov r10=ar.ssd; \ + movl r11=FPSR_DEFAULT; /* L-unit */ \ + movl r1=__gp; /* establish kernel global pointer */ \ + ;; \ + PAL_VSA_SYNC_READ_CLEANUP_PSR_PL \ + VMX_MINSTATE_END_SAVE_MIN + +/* + * SAVE_REST saves the remainder of pt_regs (with psr.ic on). + * + * Assumed state upon entry: + * psr.ic: on + * r2: points to &pt_regs.f6 + * r3: points to &pt_regs.f7 + * r4,r5,scrach + * r6: points to vpd + * r7: vpsr + * r9: contents of ar.csd + * r10: contents of ar.ssd + * r11: FPSR_DEFAULT + * + * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. + */ +#define VMX_SAVE_REST \ + tbit.z pBN0,pBN1=r7,IA64_PSR_BN_BIT; /* guest bank0 or bank1 ? */ \ + ;; \ +(pBN0) add r4=VPD(VBGR),r6; \ +(pBN0) add r5=VPD(VBGR)+0x8,r6; \ +(pBN0) add r7=VPD(VBNAT),r6; \ + ;; \ +(pBN1) add r5=VPD(VGR)+0x8,r6; \ +(pBN1) add r4=VPD(VGR),r6; \ +(pBN1) add r7=VPD(VNAT),r6; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r16,16; \ +.mem.offset 8,0; st8.spill [r5]=r17,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r18,16; \ +.mem.offset 8,0; st8.spill [r5]=r19,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r20,16; \ +.mem.offset 8,0; st8.spill [r5]=r21,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r22,16; \ +.mem.offset 8,0; st8.spill [r5]=r23,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r24,16; \ +.mem.offset 8,0; st8.spill [r5]=r25,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r26,16; \ +.mem.offset 8,0; st8.spill [r5]=r27,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r28,16; \ +.mem.offset 8,0; st8.spill [r5]=r29,16; \ + mov r26=b6; \ + ;; \ +.mem.offset 0,0; st8.spill [r4]=r30,16; \ +.mem.offset 8,0; st8.spill [r5]=r31,16; \ + mov r27=b7; \ + ;; \ + mov r30=ar.unat; \ + ;; \ + st8 [r7]=r30; \ + mov ar.fpsr=r11; /* M-unit */ \ + ;; \ + stf.spill [r2]=f6,32; \ + stf.spill [r3]=f7,32; \ + ;; \ + stf.spill [r2]=f8,32; \ + stf.spill [r3]=f9,32; \ + ;; \ + stf.spill [r2]=f10; \ + stf.spill [r3]=f11; \ + ;; \ + adds r2=PT(B6)-PT(F10),r2; \ + adds r3=PT(B7)-PT(F11),r3; \ + ;; \ + st8 [r2]=r26,16; /* b6 */ \ + st8 [r3]=r27,16; /* b7 */ \ + ;; \ + st8 [r2]=r9; /* ar.csd */ \ + st8 [r3]=r10; /* ar.ssd */ \ + ;; + +#define VMX_SAVE_MIN_WITH_COVER VMX_DO_SAVE_MIN(cover, mov r30=cr.ifs,) +#define VMX_SAVE_MIN_WITH_COVER_R19 VMX_DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19) +#define VMX_SAVE_MIN VMX_DO_SAVE_MIN( , mov r30=r0, ) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_phy_mode.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_phy_mode.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,433 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_phy_mode.c: emulating domain physical mode. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Arun Sharma (arun.sharma@xxxxxxxxx) + * Kun Tian (Kevin Tian) (kevin.tian@xxxxxxxxx) + * Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) + */ + + +#include <asm/processor.h> +#include <asm/gcc_intrin.h> +#include <asm/vmx_phy_mode.h> +#include <xen/sched.h> +#include <asm/pgtable.h> + + +int valid_mm_mode[8] = { + GUEST_PHYS, /* (it, dt, rt) -> (0, 0, 0) */ + INV_MODE, + INV_MODE, + GUEST_PHYS, /* (it, dt, rt) -> (0, 1, 1) */ + INV_MODE, + GUEST_PHYS, /* (it, dt, rt) -> (1, 0, 1) */ + INV_MODE, + GUEST_VIRT, /* (it, dt, rt) -> (1, 1, 1).*/ +}; + +/* + * Special notes: + * - Index by it/dt/rt sequence + * - Only existing mode transitions are allowed in this table + * - RSE is placed at lazy mode when emulating guest partial mode + * - If gva happens to be rr0 and rr4, only allowed case is identity + * mapping (gva=gpa), or panic! (How?) + */ +int mm_switch_table[8][8] = { + /* 2004/09/12(Kevin): Allow switch to self */ + /* + * (it,dt,rt): (0,0,0) -> (1,1,1) + * This kind of transition usually occurs in the very early + * stage of Linux boot up procedure. Another case is in efi + * and pal calls. (see "arch/ia64/kernel/head.S") + * + * (it,dt,rt): (0,0,0) -> (0,1,1) + * This kind of transition is found when OSYa exits efi boot + * service. Due to gva = gpa in this case (Same region), + * data access can be satisfied though itlb entry for physical + * emulation is hit. + */ + SW_SELF,0, 0, SW_NOP, 0, 0, 0, SW_P2V, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* + * (it,dt,rt): (0,1,1) -> (1,1,1) + * This kind of transition is found in OSYa. + * + * (it,dt,rt): (0,1,1) -> (0,0,0) + * This kind of transition is found in OSYa + */ + SW_NOP, 0, 0, SW_SELF,0, 0, 0, SW_P2V, + /* (1,0,0)->(1,1,1) */ + 0, 0, 0, 0, 0, 0, 0, SW_P2V, + /* + * (it,dt,rt): (1,0,1) -> (1,1,1) + * This kind of transition usually occurs when Linux returns + * from the low level TLB miss handlers. + * (see "arch/ia64/kernel/ivt.S") + */ + 0, 0, 0, 0, 0, SW_SELF,0, SW_P2V, + 0, 0, 0, 0, 0, 0, 0, 0, + /* + * (it,dt,rt): (1,1,1) -> (1,0,1) + * This kind of transition usually occurs in Linux low level + * TLB miss handler. (see "arch/ia64/kernel/ivt.S") + * + * (it,dt,rt): (1,1,1) -> (0,0,0) + * This kind of transition usually occurs in pal and efi calls, + * which requires running in physical mode. + * (see "arch/ia64/kernel/head.S") + * (1,1,1)->(1,0,0) + */ + + SW_V2P, 0, 0, 0, SW_V2P, SW_V2P, 0, SW_SELF, +}; + +void +physical_mode_init(VCPU *vcpu) +{ + UINT64 psr; + struct domain * d = vcpu->domain; + + vcpu->arch.old_rsc = 0; + vcpu->arch.mode_flags = GUEST_IN_PHY; +} + +extern u64 get_mfn(domid_t domid, u64 gpfn, u64 pages); +#if 0 +void +physical_itlb_miss_domn(VCPU *vcpu, u64 vadr) +{ + u64 psr; + IA64_PSR vpsr; + u64 mppn,gppn,mpp1,gpp1; + struct domain *d; + static u64 test=0; + d=vcpu->domain; + if(test) + panic("domn physical itlb miss happen\n"); + else + test=1; + vpsr.val=vmx_vcpu_get_psr(vcpu); + gppn=(vadr<<1)>>13; + mppn = get_mfn(DOMID_SELF,gppn,1); + mppn=(mppn<<12)|(vpsr.cpl<<7); + gpp1=0; + mpp1 = get_mfn(DOMID_SELF,gpp1,1); + mpp1=(mpp1<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else +// mppn |= PHY_PAGE_WB; + mpp1 |= PHY_PAGE_WB; + psr=ia64_clear_ic(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_stop(); + ia64_srlz_i(); + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} +#endif + +void +physical_itlb_miss(VCPU *vcpu, u64 vadr) +{ + physical_itlb_miss_dom0(vcpu, vadr); +} + + +void +physical_itlb_miss_dom0(VCPU *vcpu, u64 vadr) +{ + u64 psr; + IA64_PSR vpsr; + u64 mppn,gppn; + vpsr.val=vmx_vcpu_get_psr(vcpu); + gppn=(vadr<<1)>>13; + mppn = get_mfn(DOMID_SELF,gppn,1); + mppn=(mppn<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else + mppn |= PHY_PAGE_WB; + + psr=ia64_clear_ic(); + ia64_itc(1,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} + + +void +physical_dtlb_miss(VCPU *vcpu, u64 vadr) +{ + u64 psr; + IA64_PSR vpsr; + u64 mppn,gppn; +// if(vcpu->domain!=dom0) +// panic("dom n physical dtlb miss happen\n"); + vpsr.val=vmx_vcpu_get_psr(vcpu); + gppn=(vadr<<1)>>13; + mppn = get_mfn(DOMID_SELF,gppn,1); + mppn=(mppn<<12)|(vpsr.cpl<<7); + if(vadr>>63) + mppn |= PHY_PAGE_UC; + else + mppn |= PHY_PAGE_WB; + + psr=ia64_clear_ic(); + ia64_itc(2,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} + +void +vmx_init_all_rr(VCPU *vcpu) +{ + VMX(vcpu,vrr[VRN0]) = 0x38; + VMX(vcpu,vrr[VRN1]) = 0x38; + VMX(vcpu,vrr[VRN2]) = 0x38; + VMX(vcpu,vrr[VRN3]) = 0x38; + VMX(vcpu,vrr[VRN4]) = 0x38; + VMX(vcpu,vrr[VRN5]) = 0x38; + VMX(vcpu,vrr[VRN6]) = 0x60; + VMX(vcpu,vrr[VRN7]) = 0x60; + + VMX(vcpu,mrr5) = vmx_vrrtomrr(vcpu, 0x38); + VMX(vcpu,mrr6) = vmx_vrrtomrr(vcpu, 0x60); + VMX(vcpu,mrr7) = vmx_vrrtomrr(vcpu, 0x60); +} + +void +vmx_load_all_rr(VCPU *vcpu) +{ + unsigned long psr; + ia64_rr phy_rr; + + psr = ia64_clear_ic(); + + phy_rr.ps = EMUL_PHY_PAGE_SHIFT; + phy_rr.ve = 1; + + /* WARNING: not allow co-exist of both virtual mode and physical + * mode in same region + */ + if (is_physical_mode(vcpu)) { + if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) + panic("Unexpected domain switch in phy emul\n"); + phy_rr.rid = vcpu->domain->arch.metaphysical_rr0; + ia64_set_rr((VRN0 << VRN_SHIFT), phy_rr.rrval); + phy_rr.rid = vcpu->domain->arch.metaphysical_rr4; + ia64_set_rr((VRN4 << VRN_SHIFT), phy_rr.rrval); + } else { + ia64_set_rr((VRN0 << VRN_SHIFT), + vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN0]))); + ia64_set_rr((VRN4 << VRN_SHIFT), + vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN4]))); + } + +#if 1 + /* rr567 will be postponed to last point when resuming back to guest */ + ia64_set_rr((VRN1 << VRN_SHIFT), + vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN1]))); + ia64_set_rr((VRN2 << VRN_SHIFT), + vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN2]))); + ia64_set_rr((VRN3 << VRN_SHIFT), + vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN3]))); +#endif + ia64_srlz_d(); + ia64_set_psr(psr); + ia64_srlz_i(); +} + +void +switch_to_physical_rid(VCPU *vcpu) +{ + UINT64 psr; + ia64_rr phy_rr; + + phy_rr.ps = EMUL_PHY_PAGE_SHIFT; + phy_rr.ve = 1; + + /* Save original virtual mode rr[0] and rr[4] */ + psr=ia64_clear_ic(); + phy_rr.rid = vcpu->domain->arch.metaphysical_rr0; + ia64_set_rr(VRN0<<VRN_SHIFT, phy_rr.rrval); + ia64_srlz_d(); + phy_rr.rid = vcpu->domain->arch.metaphysical_rr4; + ia64_set_rr(VRN4<<VRN_SHIFT, phy_rr.rrval); + ia64_srlz_d(); + + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} + + +void +switch_to_virtual_rid(VCPU *vcpu) +{ + UINT64 psr; + ia64_rr mrr; + + psr=ia64_clear_ic(); + + mrr=vmx_vcpu_rr(vcpu,VRN0<<VRN_SHIFT); + ia64_set_rr(VRN0<<VRN_SHIFT, vmx_vrrtomrr(vcpu, mrr.rrval)); + ia64_srlz_d(); + mrr=vmx_vcpu_rr(vcpu,VRN4<<VRN_SHIFT); + ia64_set_rr(VRN4<<VRN_SHIFT, vmx_vrrtomrr(vcpu, mrr.rrval)); + ia64_srlz_d(); + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} + +static int mm_switch_action(IA64_PSR opsr, IA64_PSR npsr) +{ + return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)]; +} + +void +switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr) +{ + int act; + REGS * regs=vcpu_regs(vcpu); + act = mm_switch_action(old_psr, new_psr); + switch (act) { + case SW_V2P: + vcpu->arch.old_rsc = regs->ar_rsc; + switch_to_physical_rid(vcpu); + /* + * Set rse to enforced lazy, to prevent active rse save/restor when + * guest physical mode. + */ + regs->ar_rsc &= ~(IA64_RSC_MODE); + vcpu->arch.mode_flags |= GUEST_IN_PHY; + break; + case SW_P2V: + switch_to_virtual_rid(vcpu); + /* + * recover old mode which is saved when entering + * guest physical mode + */ + regs->ar_rsc = vcpu->arch.old_rsc; + vcpu->arch.mode_flags &= ~GUEST_IN_PHY; + break; + case SW_SELF: + printf("Switch to self-0x%lx!!! MM mode doesn't change...\n", + old_psr.val); + break; + case SW_NOP: + printf("No action required for mode transition: (0x%lx -> 0x%lx)\n", + old_psr.val, new_psr.val); + break; + default: + /* Sanity check */ + printf("old: %lx, new: %lx\n", old_psr.val, new_psr.val); + panic("Unexpected virtual <--> physical mode transition"); + break; + } + return; +} + + + +/* + * In physical mode, insert tc/tr for region 0 and 4 uses + * RID[0] and RID[4] which is for physical mode emulation. + * However what those inserted tc/tr wants is rid for + * virtual mode. So original virtual rid needs to be restored + * before insert. + * + * Operations which required such switch include: + * - insertions (itc.*, itr.*) + * - purges (ptc.* and ptr.*) + * - tpa + * - tak + * - thash?, ttag? + * All above needs actual virtual rid for destination entry. + */ + +void +check_mm_mode_switch (VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr) +{ + + if ( (old_psr.dt != new_psr.dt ) || + (old_psr.it != new_psr.it ) || + (old_psr.rt != new_psr.rt ) + ) { + switch_mm_mode (vcpu, old_psr, new_psr); + } + + return 0; +} + + +/* + * In physical mode, insert tc/tr for region 0 and 4 uses + * RID[0] and RID[4] which is for physical mode emulation. + * However what those inserted tc/tr wants is rid for + * virtual mode. So original virtual rid needs to be restored + * before insert. + * + * Operations which required such switch include: + * - insertions (itc.*, itr.*) + * - purges (ptc.* and ptr.*) + * - tpa + * - tak + * - thash?, ttag? + * All above needs actual virtual rid for destination entry. + */ + +void +prepare_if_physical_mode(VCPU *vcpu) +{ + if (is_physical_mode(vcpu)) { + vcpu->arch.mode_flags |= GUEST_PHY_EMUL; + switch_to_virtual_rid(vcpu); + } + return; +} + +/* Recover always follows prepare */ +void +recover_if_physical_mode(VCPU *vcpu) +{ + if (is_physical_mode(vcpu)) { + vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; + switch_to_physical_rid(vcpu); + } + return; +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_process.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_process.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,375 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_process.c: handling VMX architecture-related VM exits + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/smp.h> +#include <asm/ptrace.h> +#include <xen/delay.h> + +#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ +#include <asm/sal.h> /* FOR struct ia64_sal_retval */ + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/desc.h> +//#include <asm/ldt.h> +#include <xen/irq.h> +#include <xen/event.h> +#include <asm/regionreg.h> +#include <asm/privop.h> +#include <asm/ia64_int.h> +#include <asm/hpsim_ssc.h> +#include <asm/dom_fw.h> +#include <asm/vmx_vcpu.h> +#include <asm/kregs.h> +#include <asm/vmx.h> +#include <asm/vmx_mm_def.h> +#include <xen/mm.h> +/* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ +#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 + + +extern struct ia64_sal_retval pal_emulator_static(UINT64); +extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); +extern void rnat_consumption (VCPU *vcpu); +#define DOMN_PAL_REQUEST 0x110000 +IA64FAULT +vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) +{ + static int first_time = 1; + struct domain *d = (struct domain *) current->domain; + struct vcpu *v = (struct domain *) current; + extern unsigned long running_on_sim; + unsigned long i, sal_param[8]; + +#if 0 + if (first_time) { + if (platform_is_hp_ski()) running_on_sim = 1; + else running_on_sim = 0; + first_time = 0; + } + if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant + if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); + else do_ssc(vcpu_get_gr(current,36), regs); + } +#endif + if (iim == d->arch.breakimm) { + struct ia64_sal_retval x; + switch (regs->r2) { + case FW_HYPERCALL_PAL_CALL: + //printf("*** PAL hypercall: index=%d\n",regs->r28); + //FIXME: This should call a C routine + x = pal_emulator_static(VMX_VPD(v, vgr[12])); + regs->r8 = x.status; regs->r9 = x.v0; + regs->r10 = x.v1; regs->r11 = x.v2; +#if 0 + if (regs->r8) + printk("Failed vpal emulation, with index:0x%lx\n", + VMX_VPD(v, vgr[12])); +#endif + break; + case FW_HYPERCALL_SAL_CALL: + for (i = 0; i < 8; i++) + vmx_vcpu_get_gr(v, 32+i, &sal_param[i]); + x = sal_emulator(sal_param[0], sal_param[1], + sal_param[2], sal_param[3], + sal_param[4], sal_param[5], + sal_param[6], sal_param[7]); + regs->r8 = x.status; regs->r9 = x.v0; + regs->r10 = x.v1; regs->r11 = x.v2; +#if 0 + if (regs->r8) + printk("Failed vsal emulation, with index:0x%lx\n", + sal_param[0]); +#endif + break; + case FW_HYPERCALL_EFI_RESET_SYSTEM: + printf("efi.reset_system called "); + if (current->domain == dom0) { + printf("(by dom0)\n "); + (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL); + } + printf("(not supported for non-0 domain)\n"); + regs->r8 = EFI_UNSUPPORTED; + break; + case FW_HYPERCALL_EFI_GET_TIME: + { + unsigned long *tv, *tc; + vmx_vcpu_get_gr(v, 32, &tv); + vmx_vcpu_get_gr(v, 33, &tc); + printf("efi_get_time(%p,%p) called...",tv,tc); + tv = __va(translate_domain_mpaddr(tv)); + if (tc) tc = __va(translate_domain_mpaddr(tc)); + regs->r8 = (*efi.get_time)(tv,tc); + printf("and returns %lx\n",regs->r8); + } + break; + case FW_HYPERCALL_EFI_SET_TIME: + case FW_HYPERCALL_EFI_GET_WAKEUP_TIME: + case FW_HYPERCALL_EFI_SET_WAKEUP_TIME: + // FIXME: need fixes in efi.h from 2.6.9 + case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP: + // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED + // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS + // POINTER ARGUMENTS WILL BE VIRTUAL!! + case FW_HYPERCALL_EFI_GET_VARIABLE: + // FIXME: need fixes in efi.h from 2.6.9 + case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE: + case FW_HYPERCALL_EFI_SET_VARIABLE: + case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT: + // FIXME: need fixes in efi.h from 2.6.9 + regs->r8 = EFI_UNSUPPORTED; + break; + } +#if 0 + if (regs->r8) + printk("Failed vgfw emulation, with index:0x%lx\n", + regs->r2); +#endif + vmx_vcpu_increment_iip(current); + }else if(iim == DOMN_PAL_REQUEST){ + pal_emul(current); + vmx_vcpu_increment_iip(current); + } else + vmx_reflect_interruption(ifa,isr,iim,11); +} + +static UINT64 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, + 0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700,0x6800,0x6900,0x6a00, + 0x6b00,0x6c00,0x6d00,0x6e00,0x6f00,0x7000,0x7100,0x7200,0x7300,0x7400, + 0x7500,0x7600,0x7700,0x7800,0x7900,0x7a00,0x7b00,0x7c00,0x7d00,0x7e00, + 0x7f00, +}; + + + +void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, + UINT64 vector) +{ + VCPU *vcpu = current; + REGS *regs=vcpu_regs(vcpu); + UINT64 viha,vpsr = vmx_vcpu_get_psr(vcpu); + if(!(vpsr&IA64_PSR_IC)&&(vector!=5)){ + panic("Guest nested fault!"); + } + VPD_CR(vcpu,isr)=isr; + VPD_CR(vcpu,iipa) = regs->cr_iip; + vector=vec2off[vector]; + if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) + VPD_CR(vcpu,iim) = iim; + else { + set_ifa_itir_iha(vcpu,ifa,1,1,1); + } + inject_guest_interruption(vcpu, vector); +} + +// ONLY gets called from ia64_leave_kernel +// ONLY call with interrupts disabled?? (else might miss one?) +// NEVER successful if already reflecting a trap/fault because psr.i==0 +void leave_hypervisor_tail(struct pt_regs *regs) +{ + struct domain *d = current->domain; + struct vcpu *v = current; + // FIXME: Will this work properly if doing an RFI??? + if (!is_idle_task(d) ) { // always comes from guest + extern void vmx_dorfirfi(void); + struct pt_regs *user_regs = vcpu_regs(current); + + if (local_softirq_pending()) + do_softirq(); + local_irq_disable(); + + if (user_regs != regs) + printk("WARNING: checking pending interrupt in nested interrupt!!!\n"); + + /* VMX Domain N has other interrupt source, saying DM */ + if (test_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags)) + vmx_intr_assist(v); + + /* FIXME: Check event pending indicator, and set + * pending bit if necessary to inject back to guest. + * Should be careful about window between this check + * and above assist, since IOPACKET_PORT shouldn't be + * injected into vmx domain. + * + * Now hardcode the vector as 0x10 temporarily + */ + if (event_pending(v)&&(!((v->arch.arch_vmx.in_service[0])&(1UL<<0x10)))) { + VPD_CR(v, irr[0]) |= 1UL << 0x10; + v->arch.irq_new_pending = 1; + } + + if ( v->arch.irq_new_pending ) { + v->arch.irq_new_pending = 0; + vmx_check_pending_irq(v); + } + } +} + +extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); + +/* We came here because the H/W VHPT walker failed to find an entry */ +void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) +{ + IA64_PSR vpsr; + CACHE_LINE_TYPE type; + u64 vhpt_adr; + ISR misr; + ia64_rr vrr; + REGS *regs; + thash_cb_t *vtlb, *vhpt; + thash_data_t *data, me; + vtlb=vmx_vcpu_get_vtlb(vcpu); +#ifdef VTLB_DEBUG + check_vtlb_sanity(vtlb); + dump_vtlb(vtlb); +#endif + vpsr.val = vmx_vcpu_get_psr(vcpu); + regs = vcpu_regs(vcpu); + misr.val=regs->cr_isr; +/* TODO + if(vcpu->domain->id && vec == 2 && + vpsr.dt == 0 && is_gpa_io(MASK_PMA(vaddr))){ + emulate_ins(&v); + return; + } +*/ + + if((vec==1)&&(!vpsr.it)){ + physical_itlb_miss(vcpu, vadr); + return; + } + if((vec==2)&&(!vpsr.dt)){ + if(vcpu->domain!=dom0&&__gpfn_is_io(vcpu->domain,(vadr<<1)>>(PAGE_SHIFT+1))){ + emulate_io_inst(vcpu,((vadr<<1)>>1),4); // UC + }else{ + physical_dtlb_miss(vcpu, vadr); + } + return; + } + vrr = vmx_vcpu_rr(vcpu,vadr); + if(vec == 1) type = ISIDE_TLB; + else if(vec == 2) type = DSIDE_TLB; + else panic("wrong vec\n"); + +// prepare_if_physical_mode(vcpu); + + if(data=vtlb_lookup_ex(vtlb, vrr.rid, vadr,type)){ + if(vcpu->domain!=dom0&&type==DSIDE_TLB && __gpfn_is_io(vcpu->domain, data->ppn>>(PAGE_SHIFT-12))){ + vadr=(vadr&((1UL<<data->ps)-1))+(data->ppn>>(data->ps-12)<<data->ps); + emulate_io_inst(vcpu, vadr, data->ma); + return IA64_FAULT; + } + if ( data->ps != vrr.ps ) { + machine_tlb_insert(vcpu, data); + } + else { + thash_insert(vtlb->ts->vhpt,data,vadr); + } + }else if(type == DSIDE_TLB){ + if(!vhpt_enabled(vcpu, vadr, misr.rs?RSE_REF:DATA_REF)){ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, misr.val); + alt_dtlb(vcpu, vadr); + return IA64_FAULT; + } else{ + if(misr.sp){ + //TODO lds emulation + panic("Don't support speculation load"); + }else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + } else{ + vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); + vrr=vmx_vcpu_rr(vcpu,vhpt_adr); + data = vtlb_lookup_ex(vtlb, vrr.rid, vhpt_adr, DSIDE_TLB); + if(data){ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, misr.val); + dtlb_fault(vcpu, vadr); + return IA64_FAULT; + }else{ + if(misr.sp){ + //TODO lds emulation + panic("Don't support speculation load"); + }else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + }else{ + if(vpsr.ic){ + vmx_vcpu_set_isr(vcpu, misr.val); + dvhpt_fault(vcpu, vadr); + return IA64_FAULT; + }else{ + if(misr.sp){ + //TODO lds emulation + panic("Don't support speculation load"); + }else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + } + } + }else if(type == ISIDE_TLB){ + if(!vhpt_enabled(vcpu, vadr, misr.rs?RSE_REF:DATA_REF)){ + if(!vpsr.ic){ + misr.ni=1; + } + vmx_vcpu_set_isr(vcpu, misr.val); + alt_itlb(vcpu, vadr); + return IA64_FAULT; + } else{ + vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); + vrr=vmx_vcpu_rr(vcpu,vhpt_adr); + data = vtlb_lookup_ex(vtlb, vrr.rid, vhpt_adr, DSIDE_TLB); + if(data){ + if(!vpsr.ic){ + misr.ni=1; + } + vmx_vcpu_set_isr(vcpu, misr.val); + itlb_fault(vcpu, vadr); + return IA64_FAULT; + }else{ + if(!vpsr.ic){ + misr.ni=1; + } + vmx_vcpu_set_isr(vcpu, misr.val); + ivhpt_fault(vcpu, vadr); + return IA64_FAULT; + } + } + } +} + + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_support.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_support.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,164 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_support.c: vmx specific support interface. + * Copyright (c) 2005, Intel Corporation. + * Kun Tian (Kevin Tian) (Kevin.tian@xxxxxxxxx) + * + * 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. + * + */ +#include <xen/config.h> +#include <xen/sched.h> +#include <public/io/ioreq.h> +#include <asm/vmx.h> +#include <asm/vmx_vcpu.h> + +/* + * I/O emulation should be atomic from domain point of view. However, + * when emulation code is waiting for I/O completion by do_block, + * other events like DM interrupt, VBD, etc. may come and unblock + * current exection flow. So we have to prepare for re-block if unblocked + * by non I/O completion event. + */ +void vmx_wait_io(void) +{ + struct vcpu *v = current; + struct domain *d = v->domain; + extern void do_block(); + int port = iopacket_port(d); + + do { + if (!test_bit(port, + &d->shared_info->evtchn_pending[0])) + do_block(); + + /* Unblocked when some event is coming. Clear pending indication + * immediately if deciding to go for io assist + */ + if (test_and_clear_bit(port, + &d->shared_info->evtchn_pending[0])) { + clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + vmx_io_assist(v); + } + + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + /* + * Latest event is not I/O completion, so clear corresponding + * selector and pending indication, to allow real event coming + */ + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + + /* Here atually one window is leaved before selector is cleared. + * However this window only delay the indication to coming event, + * nothing losed. Next loop will check I/O channel to fix this + * window. + */ + clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + } + else + break; + } while (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)); +} + +/* + * Only place to call vmx_io_assist is mmio/legacy_io emulation. + * Since I/O emulation is synchronous, it shouldn't be called in + * other places. This is not like x86, since IA-64 implements a + * per-vp stack without continuation. + */ +void vmx_io_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + ioreq_t *p; + + /* + * This shared page contains I/O request between emulation code + * and device model. + */ + vio = get_vio(v->domain, v->vcpu_id); + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + + p = &vio->vp_ioreq; + + if (p->state == STATE_IORESP_HOOK) + panic("Not supported: No hook available for DM request\n"); + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + if (p->state != STATE_IORESP_READY) { + /* Can't do_block here, for the same reason as other places to + * use vmx_wait_io. Simple return is safe since vmx_wait_io will + * try to block again + */ + return; + } else + p->state = STATE_INVALID; + + clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + } else + return; /* Spurous event? */ +} + +/* + * VMX domainN has two types of interrupt source: lsapic model within + * HV, and device model within domain 0 (service OS). There're another + * pending array in share page, manipulated by device model directly. + * To conform to VT-i spec, we have to sync pending bits in shared page + * into VPD. This has to be done before checking pending interrupt at + * resume to guest. For domain 0, all the interrupt sources come from + * HV, which then doesn't require this assist. + */ +void vmx_intr_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + struct domain *d = v->domain; + extern void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, + unsigned long *pend_irr); + int port = iopacket_port(d); + + /* I/O emulation is atomic, so it's impossible to see execution flow + * out of vmx_wait_io, when guest is still waiting for response. + */ + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) + panic("!!!Bad resume to guest before I/O emulation is done.\n"); + + /* Clear indicator specific to interrupt delivered from DM */ + if (test_and_clear_bit(port, + &d->shared_info->evtchn_pending[0])) { + if (!d->shared_info->evtchn_pending[port >> 5]) + clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + + if (!v->vcpu_info->evtchn_pending_sel) + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + } + + /* Even without event pending, we still need to sync pending bits + * between DM and vlsapic. The reason is that interrupt delivery + * shares same event channel as I/O emulation, with corresponding + * indicator possibly cleared when vmx_wait_io(). + */ + vio = get_vio(v->domain, v->vcpu_id); + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + +#ifdef V_IOSAPIC_READY + vlapic_update_ext_irq(v); +#else + panic("IOSAPIC model is missed in qemu\n"); +#endif + return; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_utility.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_utility.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,659 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_utility.c: + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> + * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <xen/types.h> +#include <asm/vmx_vcpu.h> +#include <asm/processor.h> +#include <asm/vmx_mm_def.h> + + +/* + * Return: + * 0: Not reserved indirect registers + * 1: Is reserved indirect registers + */ +int +is_reserved_indirect_register ( + int type, + int index ) +{ + switch (type) { + case IA64_CPUID: + if ( index >= 5 ) { + return 1; + } + + case IA64_DBR: + case IA64_IBR: + //bugbugbug:check with pal about the max ibr/dbr!!!! + break; + + case IA64_PMC: + //bugbugbug:check with pal about the max ibr/dbr!!!! + break; + + case IA64_PMD: + //bugbugbug:check with pal about the max ibr/dbr!!!! + break; + + case IA64_PKR: + //bugbugbug:check with pal about the max pkr!!!! + break; + + case IA64_RR: + //bugbugbug:check with pal about the max rr!!!! + break; + + default: + panic ("Unsupported instruction!"); + } + + return 0; + +} + +/* + * Return: + * Set all ignored fields in value to 0 and return + */ +u64 +indirect_reg_igfld_MASK ( + int type, + int index, + u64 value + ) +{ + u64 nvalue; + + nvalue = value; + switch ( type ) { + case IA64_CPUID: + if ( index == 2 ) { + nvalue = 0; + } + break; + + case IA64_DBR: + case IA64_IBR: + /* Refer to SDM Vol2 Table 7-1,7-2 */ + if ( index % 2 != 0) { + /* Ignore field: {61:60} */ + nvalue = value & (~MASK (60, 2)); + } + break; + case IA64_PMC: + if ( index == 0 ) { + /* Ignore field: 3:1 */ + nvalue = value & (~MASK (1, 3)); + } + break; + case IA64_PMD: + if ( index >= 4 ) { + /* Ignore field: 7:7 */ + /* bugbug: this code is correct for generic + * PMD. However, for implementation specific + * PMD, it's WRONG. need more info to judge + * what's implementation specific PMD. + */ + nvalue = value & (~MASK (7, 1)); + } + break; + case IA64_PKR: + case IA64_RR: + break; + default: + panic ("Unsupported instruction!"); + } + + return nvalue; +} + +/* + * Return: + * Set all ignored fields in value to 0 and return + */ +u64 +cr_igfld_mask (int index, u64 value) +{ + u64 nvalue; + + nvalue = value; + + switch ( index ) { + case IA64_REG_CR_IVA: + /* Ignore filed: 14:0 */ + nvalue = value & (~MASK (0, 15)); + break; + + case IA64_REG_CR_IHA: + /* Ignore filed: 1:0 */ + nvalue = value & (~MASK (0, 2)); + break; + + case IA64_REG_CR_LID: + /* Ignore filed: 63:32 */ + nvalue = value & (~MASK (32, 32)); + break; + + case IA64_REG_CR_TPR: + /* Ignore filed: 63:17,3:0 */ + nvalue = value & (~MASK (17, 47)); + nvalue = nvalue & (~MASK (0, 4)); + break; + + case IA64_REG_CR_EOI: + /* Ignore filed: 63:0 */ + nvalue = 0; + break; + + case IA64_REG_CR_ITV: + case IA64_REG_CR_PMV: + case IA64_REG_CR_CMCV: + case IA64_REG_CR_LRR0: + case IA64_REG_CR_LRR1: + /* Ignore filed: 63:17,12:12 */ + nvalue = value & (~MASK (17, 47)); + nvalue = nvalue & (~MASK (12, 1)); + break; + } + + return nvalue; +} + + +/* + * Return: + * 1: PSR reserved fields are not zero + * 0: PSR reserved fields are all zero + */ +int +check_psr_rsv_fields (u64 value) +{ + /* PSR reserved fields: 0, 12~6, 16, 31~28, 63~46 + * These reserved fields shall all be zero + * Otherwise we will panic + */ + + if ( value & MASK (0, 1) || + value & MASK (6, 7) || + value & MASK (16, 1) || + value & MASK (28, 4) || + value & MASK (46, 18) + ) { + return 1; + } + + return 0; +} + + + +/* + * Return: + * 1: CR reserved fields are not zero + * 0: CR reserved fields are all zero + */ +int +check_cr_rsv_fields (int index, u64 value) +{ + switch (index) { + case IA64_REG_CR_DCR: + if ( (value & MASK ( 3, 5 )) || + (value & MASK (15, 49))) { + return 1; + } + return 0; + + case IA64_REG_CR_ITM: + case IA64_REG_CR_IVA: + case IA64_REG_CR_IIP: + case IA64_REG_CR_IFA: + case IA64_REG_CR_IIPA: + case IA64_REG_CR_IIM: + case IA64_REG_CR_IHA: + case IA64_REG_CR_EOI: + return 0; + + case IA64_REG_CR_PTA: + if ( (value & MASK ( 1, 1 )) || + (value & MASK (9, 6))) { + return 1; + } + return 0; + + case IA64_REG_CR_IPSR: + return check_psr_rsv_fields (value); + + + case IA64_REG_CR_ISR: + if ( (value & MASK ( 24, 8 )) || + (value & MASK (44, 20))) { + return 1; + } + return 0; + + case IA64_REG_CR_ITIR: + if ( (value & MASK ( 0, 2 )) || + (value & MASK (32, 32))) { + return 1; + } + return 0; + + case IA64_REG_CR_IFS: + if ( (value & MASK ( 38, 25 ))) { + return 1; + } + return 0; + + case IA64_REG_CR_LID: + if ( (value & MASK ( 0, 16 ))) { + return 1; + } + return 0; + + case IA64_REG_CR_IVR: + if ( (value & MASK ( 8, 56 ))) { + return 1; + } + return 0; + + case IA64_REG_CR_TPR: + if ( (value & MASK ( 8, 8 ))) { + return 1; + } + return 0; + + case IA64_REG_CR_IRR0: + if ( (value & MASK ( 1, 1 )) || + (value & MASK (3, 13))) { + return 1; + } + return 0; + + case IA64_REG_CR_ITV: + case IA64_REG_CR_PMV: + case IA64_REG_CR_CMCV: + if ( (value & MASK ( 8, 4 )) || + (value & MASK (13, 3))) { + return 1; + } + return 0; + + case IA64_REG_CR_LRR0: + case IA64_REG_CR_LRR1: + if ( (value & MASK ( 11, 1 )) || + (value & MASK (14, 1))) { + return 1; + } + return 0; + } + + + panic ("Unsupported CR"); +} + + + +/* + * Return: + * 0: Indirect Reg reserved fields are not zero + * 1: Indirect Reg reserved fields are all zero + */ +int +check_indirect_reg_rsv_fields ( int type, int index, u64 value ) +{ + + switch ( type ) { + case IA64_CPUID: + if ( index == 3 ) { + if ( value & MASK (40, 24 )) { + return 0; + } + } else if ( index == 4 ) { + if ( value & MASK (2, 62 )) { + return 0; + } + } + break; + + case IA64_DBR: + case IA64_IBR: + case IA64_PMC: + case IA64_PMD: + break; + + case IA64_PKR: + if ( value & MASK (4, 4) || + value & MASK (32, 32 )) { + return 0; + } + break; + + case IA64_RR: + if ( value & MASK (1, 1) || + value & MASK (32, 32 )) { + return 0; + } + break; + + default: + panic ("Unsupported instruction!"); + } + + return 1; +} + + + + +/* Return + * Same format as isr_t + * Only ei/ni bits are valid, all other bits are zero + */ +u64 +set_isr_ei_ni (VCPU *vcpu) +{ + + IA64_PSR vpsr,ipsr; + ISR visr; + REGS *regs; + + regs=vcpu_regs(vcpu); + + visr.val = 0; + + vpsr.val = vmx_vcpu_get_psr (vcpu); + + if (!vpsr.ic == 1 ) { + /* Set ISR.ni */ + visr.ni = 1; + } + ipsr.val = regs->cr_ipsr; + + visr.ei = ipsr.ri; + return visr.val; +} + + +/* Set up ISR.na/code{3:0}/r/w for no-access instructions + * Refer to SDM Vol Table 5-1 + * Parameter: + * setr: if 1, indicates this function will set up ISR.r + * setw: if 1, indicates this function will set up ISR.w + * Return: + * Same format as ISR. All fields are zero, except na/code{3:0}/r/w + */ +u64 +set_isr_for_na_inst(VCPU *vcpu, int op) +{ + ISR visr; + visr.val = 0; + switch (op) { + case IA64_INST_TPA: + visr.na = 1; + visr.code = 0; + break; + case IA64_INST_TAK: + visr.na = 1; + visr.code = 3; + break; + } + return visr.val; +} + + + +/* + * Set up ISR for registe Nat consumption fault + * Parameters: + * read: if 1, indicates this is a read access; + * write: if 1, indicates this is a write access; + */ +void +set_rnat_consumption_isr (VCPU *vcpu,int inst,int read,int write) +{ + ISR visr; + u64 value; + /* Need set up ISR: code, ei, ni, na, r/w */ + visr.val = 0; + + /* ISR.code{7:4} =1, + * Set up ISR.code{3:0}, ISR.na + */ + visr.code = (1 << 4); + if (inst) { + + value = set_isr_for_na_inst (vcpu,inst); + visr.val = visr.val | value; + } + + /* Set up ISR.r/w */ + visr.r = read; + visr.w = write; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr (vcpu,visr.val); +} + + + +/* + * Set up ISR for break fault + */ +void set_break_isr (VCPU *vcpu) +{ + ISR visr; + u64 value; + + /* Need set up ISR: ei, ni */ + + visr.val = 0; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr(vcpu, visr.val); +} + + + + + + +/* + * Set up ISR for Priviledged Operation fault + */ +void set_privileged_operation_isr (VCPU *vcpu,int inst) +{ + ISR visr; + u64 value; + + /* Need set up ISR: code, ei, ni, na */ + + visr.val = 0; + + /* Set up na, code{3:0} for no-access instruction */ + value = set_isr_for_na_inst (vcpu, inst); + visr.val = visr.val | value; + + + /* ISR.code{7:4} =1 */ + visr.code = (1 << 4) | visr.code; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr (vcpu, visr.val); +} + + + + +/* + * Set up ISR for Priviledged Register fault + */ +void set_privileged_reg_isr (VCPU *vcpu, int inst) +{ + ISR visr; + u64 value; + + /* Need set up ISR: code, ei, ni */ + + visr.val = 0; + + /* ISR.code{7:4} =2 */ + visr.code = 2 << 4; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr (vcpu, visr.val); +} + + + + + +/* + * Set up ISR for Reserved Register/Field fault + */ +void set_rsv_reg_field_isr (VCPU *vcpu) +{ + ISR visr; + u64 value; + + /* Need set up ISR: code, ei, ni */ + + visr.val = 0; + + /* ISR.code{7:4} =4 */ + visr.code = (3 << 4) | visr.code; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr (vcpu, visr.val); +} + + + +/* + * Set up ISR for Illegal Operation fault + */ +void set_illegal_op_isr (VCPU *vcpu) +{ + ISR visr; + u64 value; + + /* Need set up ISR: ei, ni */ + + visr.val = 0; + + /* Set up ei/ni */ + value = set_isr_ei_ni (vcpu); + visr.val = visr.val | value; + + vmx_vcpu_set_isr (vcpu, visr.val); +} + + +void set_isr_reg_nat_consumption(VCPU *vcpu, u64 flag, u64 non_access) +{ + ISR isr; + + isr.val = 0; + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_REG_NAT_CONSUMPTION_FAULT | flag; + isr.na = non_access; + isr.r = 1; + isr.w = 0; + vmx_vcpu_set_isr(vcpu, isr.val); + return; +} + +void set_isr_for_priv_fault(VCPU *vcpu, u64 non_access) +{ + u64 value; + ISR isr; + + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_PRIV_OP_FAULT; + isr.na = non_access; + vmx_vcpu_set_isr(vcpu, isr.val); + + return; +} + + +IA64FAULT check_target_register(VCPU *vcpu, u64 reg_index) +{ + u64 sof; + REGS *regs; + regs=vcpu_regs(vcpu); + sof = regs->cr_ifs & 0x7f; + if(reg_index >= sof + 32) + return IA64_FAULT; + return IA64_NO_FAULT;; +} + + +int is_reserved_rr_register(VCPU* vcpu, int reg_index) +{ + return (reg_index >= 8); +} + +#define ITIR_RSV_MASK (0x3UL | (((1UL<<32)-1) << 32)) +int is_reserved_itir_field(VCPU* vcpu, u64 itir) +{ + if ( itir & ITIR_RSV_MASK ) { + return 1; + } + return 0; +} + +int is_reserved_rr_field(VCPU* vcpu, u64 reg_value) +{ + ia64_rr rr; + rr.rrval = reg_value; + + if(rr.reserved0 != 0 || rr.reserved1 != 0){ + return 1; + } + if(rr.ps < 12 || rr.ps > 28){ + // page too big or small. + return 1; + } + if(rr.ps > 15 && rr.ps % 2 != 0){ + // unsupported page size. + return 1; + } + return 0; +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_vcpu.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_vcpu.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,446 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_vcpu.c: handling all virtual cpu related thing. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Fred yang (fred.yang@xxxxxxxxx) + * Arun Sharma (arun.sharma@xxxxxxxxx) + * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <xen/sched.h> +#include <public/arch-ia64.h> +#include <asm/ia64_int.h> +#include <asm/vmx_vcpu.h> +#include <asm/regionreg.h> +#include <asm/tlb.h> +#include <asm/processor.h> +#include <asm/delay.h> +#include <asm/regs.h> +#include <asm/gcc_intrin.h> +#include <asm/vmx_mm_def.h> +#include <asm/vmx.h> + +//u64 fire_itc; +//u64 fire_itc2; +//u64 fire_itm; +//u64 fire_itm2; +/* + * Copyright (c) 2005 Intel Corporation. + * Anthony Xu (anthony.xu@xxxxxxxxx) + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + * + * 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. + * + */ + +/************************************************************************** + VCPU general register access routines +**************************************************************************/ +#include <asm/hw_irq.h> +#include <asm/vmx_pal_vsa.h> +#include <asm/kregs.h> + +//unsigned long last_guest_rsm = 0x0; +struct guest_psr_bundle{ + unsigned long ip; + unsigned long psr; +}; + +struct guest_psr_bundle guest_psr_buf[100]; +unsigned long guest_psr_index = 0; + +void +vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value) +{ + + UINT64 mask; + REGS *regs; + IA64_PSR old_psr, new_psr; + old_psr.val=vmx_vcpu_get_psr(vcpu); + + regs=vcpu_regs(vcpu); + /* We only support guest as: + * vpsr.pk = 0 + * vpsr.is = 0 + * Otherwise panic + */ + if ( value & (IA64_PSR_PK | IA64_PSR_IS | IA64_PSR_VM )) { + panic ("Setting unsupport guest psr!"); + } + + /* + * For those IA64_PSR bits: id/da/dd/ss/ed/ia + * Since these bits will become 0, after success execution of each + * instruction, we will change set them to mIA64_PSR + */ + VMX_VPD(vcpu,vpsr) = value & + (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA + )); + + if ( !old_psr.i && (value & IA64_PSR_I) ) { + // vpsr.i 0->1 + vcpu->arch.irq_new_condition = 1; + } + new_psr.val=vmx_vcpu_get_psr(vcpu); + { + struct pt_regs *regs = vcpu_regs(vcpu); + guest_psr_buf[guest_psr_index].ip = regs->cr_iip; + guest_psr_buf[guest_psr_index].psr = new_psr.val; + if (++guest_psr_index >= 100) + guest_psr_index = 0; + } +#if 0 + if (old_psr.i != new_psr.i) { + if (old_psr.i) + last_guest_rsm = vcpu_regs(vcpu)->cr_iip; + else + last_guest_rsm = 0; + } +#endif + + /* + * All vIA64_PSR bits shall go to mPSR (v->tf->tf_special.psr) + * , except for the following bits: + * ic/i/dt/si/rt/mc/it/bn/vm + */ + mask = IA64_PSR_IC + IA64_PSR_I + IA64_PSR_DT + IA64_PSR_SI + + IA64_PSR_RT + IA64_PSR_MC + IA64_PSR_IT + IA64_PSR_BN + + IA64_PSR_VM; + + regs->cr_ipsr = (regs->cr_ipsr & mask ) | ( value & (~mask) ); + + check_mm_mode_switch(vcpu, old_psr, new_psr); + return IA64_NO_FAULT; +} + +/* Adjust slot both in pt_regs and vpd, upon vpsr.ri which + * should have sync with ipsr in entry. + * + * Clear some bits due to successfully emulation. + */ +IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu) +{ + // TODO: trap_bounce?? Eddie + REGS *regs = vcpu_regs(vcpu); + IA64_PSR vpsr; + IA64_PSR *ipsr = (IA64_PSR *)®s->cr_ipsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + if (vpsr.ri == 2) { + vpsr.ri = 0; + regs->cr_iip += 16; + } else { + vpsr.ri++; + } + + ipsr->ri = vpsr.ri; + vpsr.val &= + (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA + )); + + VMX_VPD(vcpu, vpsr) = vpsr.val; + + ipsr->val &= + (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA + )); + + return (IA64_NO_FAULT); +} + + +IA64FAULT vmx_vcpu_cover(VCPU *vcpu) +{ + REGS *regs = vcpu_regs(vcpu); + IA64_PSR vpsr; + vpsr.val = vmx_vcpu_get_psr(vcpu); + + if(!vpsr.ic) + VPD_CR(vcpu,ifs) = regs->cr_ifs; + regs->cr_ifs = IA64_IFS_V; + return (IA64_NO_FAULT); +} + + +thash_cb_t * +vmx_vcpu_get_vtlb(VCPU *vcpu) +{ + return vcpu->arch.vtlb; +} + + +struct virutal_platform_def * +vmx_vcpu_get_plat(VCPU *vcpu) +{ + return &(vcpu->domain->arch.vmx_platform); +} + + +ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr) +{ + return (ia64_rr)VMX(vcpu,vrr[vadr>>61]); +} + + +IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) +{ + ia64_rr oldrr,newrr; + thash_cb_t *hcb; + oldrr=vmx_vcpu_rr(vcpu,reg); + newrr.rrval=val; +#if 1 + if(oldrr.ps!=newrr.ps){ + hcb = vmx_vcpu_get_vtlb(vcpu); + thash_purge_all(hcb); + } +#endif + VMX(vcpu,vrr[reg>>61]) = val; + switch((u64)(reg>>61)) { + case VRN5: + VMX(vcpu,mrr5)=vmx_vrrtomrr(vcpu,val); + break; + case VRN6: + VMX(vcpu,mrr6)=vmx_vrrtomrr(vcpu,val); + break; + case VRN7: + VMX(vcpu,mrr7)=vmx_vrrtomrr(vcpu,val); + /* Change double mapping for this domain */ +#ifdef XEN_DBL_MAPPING + vmx_change_double_mapping(vcpu, + vmx_vrrtomrr(vcpu,oldrr.rrval), + vmx_vrrtomrr(vcpu,newrr.rrval)); +#endif + break; + default: + ia64_set_rr(reg,vmx_vrrtomrr(vcpu,val)); + break; + } + + return (IA64_NO_FAULT); +} + + + +/************************************************************************** + VCPU protection key register access routines +**************************************************************************/ + +IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + UINT64 val = (UINT64)ia64_get_pkr(reg); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val) +{ + ia64_set_pkr(reg,val); + return (IA64_NO_FAULT); +} + +#if 0 +int tlb_debug=0; +check_entry(u64 va, u64 ps, char *str) +{ + va &= ~ (PSIZE(ps)-1); + if ( va == 0x2000000002908000UL || + va == 0x600000000000C000UL ) { + stop(); + } + if (tlb_debug) printf("%s at %lx %lx\n", str, va, 1UL<<ps); +} +#endif + + +u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa) +{ + ia64_rr rr,rr1; + rr=vmx_vcpu_rr(vcpu,ifa); + rr1.rrval=0; + rr1.ps=rr.ps; + rr1.rid=rr.rid; + return (rr1.rrval); +} + + + + +IA64FAULT vmx_vcpu_rfi(VCPU *vcpu) +{ + // TODO: Only allowed for current vcpu + UINT64 ifs, psr; + REGS *regs = vcpu_regs(vcpu); + psr = VPD_CR(vcpu,ipsr); + vmx_vcpu_set_psr(vcpu,psr); + ifs=VPD_CR(vcpu,ifs); + if((ifs>>63)&&(ifs<<1)){ + ifs=(regs->cr_ifs)&0x7f; + regs->rfi_pfs = (ifs<<7)|ifs; + regs->cr_ifs = VPD_CR(vcpu,ifs); + } + regs->cr_iip = VPD_CR(vcpu,iip); + return (IA64_NO_FAULT); +} + + +UINT64 +vmx_vcpu_get_psr(VCPU *vcpu) +{ + return VMX_VPD(vcpu,vpsr); +} + + +IA64FAULT +vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val) +{ + IA64_PSR vpsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + if ( vpsr.bn ) { + *val=VMX_VPD(vcpu,vgr[reg-16]); + // Check NAT bit + if ( VMX_VPD(vcpu,vnat) & (1UL<<(reg-16)) ) { + // TODO + //panic ("NAT consumption fault\n"); + return IA64_FAULT; + } + + } + else { + *val=VMX_VPD(vcpu,vbgr[reg-16]); + if ( VMX_VPD(vcpu,vbnat) & (1UL<<reg) ) { + //panic ("NAT consumption fault\n"); + return IA64_FAULT; + } + + } + return IA64_NO_FAULT; +} + +IA64FAULT +vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat) +{ + IA64_PSR vpsr; + vpsr.val = vmx_vcpu_get_psr(vcpu); + if ( vpsr.bn ) { + VMX_VPD(vcpu,vgr[reg-16]) = val; + if(nat){ + VMX_VPD(vcpu,vnat) |= ( 1UL<<(reg-16) ); + }else{ + VMX_VPD(vcpu,vbnat) &= ~( 1UL<<(reg-16) ); + } + } + else { + VMX_VPD(vcpu,vbgr[reg-16]) = val; + if(nat){ + VMX_VPD(vcpu,vnat) |= ( 1UL<<(reg) ); + }else{ + VMX_VPD(vcpu,vbnat) &= ~( 1UL<<(reg) ); + } + } + return IA64_NO_FAULT; +} + + + +IA64FAULT +vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val) +{ + REGS *regs=vcpu_regs(vcpu); + int nat; + //TODO, Eddie + if (!regs) return 0; + if (reg >= 16 && reg < 32) { + return vmx_vcpu_get_bgr(vcpu,reg,val); + } + getreg(reg,val,&nat,regs); // FIXME: handle NATs later + if(nat){ + return IA64_FAULT; + } + return IA64_NO_FAULT; +} + +// returns: +// IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault +// IA64_NO_FAULT otherwise + +IA64FAULT +vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat) +{ + REGS *regs = vcpu_regs(vcpu); + long sof = (regs->cr_ifs) & 0x7f; + //TODO Eddie + + if (!regs) return IA64_ILLOP_FAULT; + if (reg >= sof + 32) return IA64_ILLOP_FAULT; + if ( reg >= 16 && reg < 32 ) { + return vmx_vcpu_set_bgr(vcpu,reg, value, nat); + } + setreg(reg,value,nat,regs); + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) +{ + UINT64 vpsr; + vpsr = vmx_vcpu_get_psr(vcpu); + vpsr &= (~imm24); + vmx_vcpu_set_psr(vcpu, vpsr); + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) +{ + UINT64 vpsr; + vpsr = vmx_vcpu_get_psr(vcpu); + vpsr |= imm24; + vmx_vcpu_set_psr(vcpu, vpsr); + return IA64_NO_FAULT; +} + + +IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val) +{ + vmx_vcpu_set_psr(vcpu, val); + return IA64_NO_FAULT; +} + +IA64FAULT +vmx_vcpu_set_tpr(VCPU *vcpu, u64 val) +{ + VPD_CR(vcpu,tpr)=val; + vcpu->arch.irq_new_condition = 1; + return IA64_NO_FAULT; +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_virt.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_virt.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1511 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_virt.c: + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Fred yang (fred.yang@xxxxxxxxx) + * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + + + +#include <asm/privop.h> +#include <asm/vmx_vcpu.h> +#include <asm/processor.h> +#include <asm/delay.h> // Debug only +#include <asm/vmmu.h> +#include <asm/vmx_mm_def.h> +#include <asm/smp.h> + +#include <asm/virt_event.h> +extern UINT64 privop_trace; + +void +ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause) +{ + *cause=0; + switch (slot_type) { + case M: + if (inst.generic.major==0){ + if(inst.M28.x3==0){ + if(inst.M44.x4==6){ + *cause=EVENT_SSM; + }else if(inst.M44.x4==7){ + *cause=EVENT_RSM; + }else if(inst.M30.x4==8&&inst.M30.x2==2){ + *cause=EVENT_MOV_TO_AR_IMM; + } + } + } + else if(inst.generic.major==1){ + if(inst.M28.x3==0){ + if(inst.M32.x6==0x2c){ + *cause=EVENT_MOV_TO_CR; + }else if(inst.M33.x6==0x24){ + *cause=EVENT_MOV_FROM_CR; + }else if(inst.M35.x6==0x2d){ + *cause=EVENT_MOV_TO_PSR; + }else if(inst.M36.x6==0x25){ + *cause=EVENT_MOV_FROM_PSR; + }else if(inst.M29.x6==0x2A){ + *cause=EVENT_MOV_TO_AR; + }else if(inst.M31.x6==0x22){ + *cause=EVENT_MOV_FROM_AR; + }else if(inst.M45.x6==0x09){ + *cause=EVENT_PTC_L; + }else if(inst.M45.x6==0x0A){ + *cause=EVENT_PTC_G; + }else if(inst.M45.x6==0x0B){ + *cause=EVENT_PTC_GA; + }else if(inst.M45.x6==0x0C){ + *cause=EVENT_PTR_D; + }else if(inst.M45.x6==0x0D){ + *cause=EVENT_PTR_I; + }else if(inst.M46.x6==0x1A){ + *cause=EVENT_THASH; + }else if(inst.M46.x6==0x1B){ + *cause=EVENT_TTAG; + }else if(inst.M46.x6==0x1E){ + *cause=EVENT_TPA; + }else if(inst.M46.x6==0x1F){ + *cause=EVENT_TAK; + }else if(inst.M47.x6==0x34){ + *cause=EVENT_PTC_E; + }else if(inst.M41.x6==0x2E){ + *cause=EVENT_ITC_D; + }else if(inst.M41.x6==0x2F){ + *cause=EVENT_ITC_I; + }else if(inst.M42.x6==0x00){ + *cause=EVENT_MOV_TO_RR; + }else if(inst.M42.x6==0x01){ + *cause=EVENT_MOV_TO_DBR; + }else if(inst.M42.x6==0x02){ + *cause=EVENT_MOV_TO_IBR; + }else if(inst.M42.x6==0x03){ + *cause=EVENT_MOV_TO_PKR; + }else if(inst.M42.x6==0x04){ + *cause=EVENT_MOV_TO_PMC; + }else if(inst.M42.x6==0x05){ + *cause=EVENT_MOV_TO_PMD; + }else if(inst.M42.x6==0x0E){ + *cause=EVENT_ITR_D; + }else if(inst.M42.x6==0x0F){ + *cause=EVENT_ITR_I; + }else if(inst.M43.x6==0x10){ + *cause=EVENT_MOV_FROM_RR; + }else if(inst.M43.x6==0x11){ + *cause=EVENT_MOV_FROM_DBR; + }else if(inst.M43.x6==0x12){ + *cause=EVENT_MOV_FROM_IBR; + }else if(inst.M43.x6==0x13){ + *cause=EVENT_MOV_FROM_PKR; + }else if(inst.M43.x6==0x14){ + *cause=EVENT_MOV_FROM_PMC; +/* + }else if(inst.M43.x6==0x15){ + *cause=EVENT_MOV_FROM_PMD; +*/ + }else if(inst.M43.x6==0x17){ + *cause=EVENT_MOV_FROM_CPUID; + } + } + } + break; + case B: + if(inst.generic.major==0){ + if(inst.B8.x6==0x02){ + *cause=EVENT_COVER; + }else if(inst.B8.x6==0x08){ + *cause=EVENT_RFI; + }else if(inst.B8.x6==0x0c){ + *cause=EVENT_BSW_0; + }else if(inst.B8.x6==0x0d){ + *cause=EVENT_BSW_1; + } + } + } +} + +IA64FAULT vmx_emul_rsm(VCPU *vcpu, INST64 inst) +{ + UINT64 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; + return vmx_vcpu_set_psr_sm(vcpu,imm24); +} + +unsigned long last_guest_psr = 0x0; +IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst) +{ + UINT64 tgt = inst.M33.r1; + UINT64 val; + IA64FAULT fault; + +/* + if ((fault = vmx_vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) + return vmx_vcpu_set_gr(vcpu, tgt, val); + else return fault; + */ + val = vmx_vcpu_get_psr(vcpu); + val = (val & MASK(0, 32)) | (val & MASK(35, 2)); + last_guest_psr = val; + return vmx_vcpu_set_gr(vcpu, tgt, val, 0); +} + +/** + * @todo Check for reserved bits and return IA64_RSVDREG_FAULT. + */ +IA64FAULT vmx_emul_mov_to_psr(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + if(vmx_vcpu_get_gr(vcpu, inst.M35.r2, &val) != IA64_NO_FAULT) + panic(" get_psr nat bit fault\n"); + + val = (val & MASK(0, 32)) | (VMX_VPD(vcpu, vpsr) & MASK(32, 32)); +#if 0 + if (last_mov_from_psr && (last_guest_psr != (val & MASK(0,32)))) + while(1); + else + last_mov_from_psr = 0; +#endif + return vmx_vcpu_set_psr_l(vcpu,val); +} + + +/************************************************************************** +Privileged operation emulation routines +**************************************************************************/ + +IA64FAULT vmx_emul_rfi(VCPU *vcpu, INST64 inst) +{ + IA64_PSR vpsr; + REGS *regs; +#ifdef CHECK_FAULT + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + regs=vcpu_regs(vcpu); + vpsr.val=regs->cr_ipsr; + if ( vpsr.is == 1 ) { + panic ("We do not support IA32 instruction yet"); + } + + return vmx_vcpu_rfi(vcpu); +} + +IA64FAULT vmx_emul_bsw0(VCPU *vcpu, INST64 inst) +{ +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + return vmx_vcpu_bsw0(vcpu); +} + +IA64FAULT vmx_emul_bsw1(VCPU *vcpu, INST64 inst) +{ +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + return vmx_vcpu_bsw1(vcpu); +} + +IA64FAULT vmx_emul_cover(VCPU *vcpu, INST64 inst) +{ + return vmx_vcpu_cover(vcpu); +} + +IA64FAULT vmx_emul_ptc_l(VCPU *vcpu, INST64 inst) +{ + u64 r2,r3; + ISR isr; + IA64_PSR vpsr; + + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&r2)){ +#ifdef VMAL_NO_FAULT_CHECK + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif // VMAL_NO_FAULT_CHECK + } +#ifdef VMAL_NO_FAULT_CHECK + if (unimplemented_gva(vcpu,r3) ) { + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + return vmx_vcpu_ptc_l(vcpu,r3,bits(r2,2,7)); +} + +IA64FAULT vmx_emul_ptc_e(VCPU *vcpu, INST64 inst) +{ + u64 r3; + ISR isr; + IA64_PSR vpsr; + + vpsr.val=vmx_vcpu_get_psr(vcpu); +#ifdef VMAL_NO_FAULT_CHECK + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + if(vmx_vcpu_get_gr(vcpu,inst.M47.r3,&r3)){ +#ifdef VMAL_NO_FAULT_CHECK + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif // VMAL_NO_FAULT_CHECK + } + return vmx_vcpu_ptc_e(vcpu,r3); +} + +IA64FAULT vmx_emul_ptc_g(VCPU *vcpu, INST64 inst) +{ + return vmx_emul_ptc_l(vcpu, inst); +} + +IA64FAULT vmx_emul_ptc_ga(VCPU *vcpu, INST64 inst) +{ + return vmx_emul_ptc_l(vcpu, inst); +} + +IA64FAULT ptr_fault_check(VCPU *vcpu, INST64 inst, u64 *pr2, u64 *pr3) +{ + ISR isr; + IA64FAULT ret1, ret2; + +#ifdef VMAL_NO_FAULT_CHECK + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + ret1 = vmx_vcpu_get_gr(vcpu,inst.M45.r3,pr3); + ret2 = vmx_vcpu_get_gr(vcpu,inst.M45.r2,pr2); +#ifdef VMAL_NO_FAULT_CHECK + if ( ret1 != IA64_NO_FAULT || ret2 != IA64_NO_FAULT ) { + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; + } + if (unimplemented_gva(vcpu,r3) ) { + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + return IA64_NO_FAULT; +} + +IA64FAULT vmx_emul_ptr_d(VCPU *vcpu, INST64 inst) +{ + u64 r2,r3; + if ( ptr_fault_check(vcpu, inst, &r2, &r3 ) == IA64_FAULT ) + return IA64_FAULT; + return vmx_vcpu_ptr_d(vcpu,r3,bits(r2,2,7)); +} + +IA64FAULT vmx_emul_ptr_i(VCPU *vcpu, INST64 inst) +{ + u64 r2,r3; + if ( ptr_fault_check(vcpu, inst, &r2, &r3 ) == IA64_FAULT ) + return IA64_FAULT; + return vmx_vcpu_ptr_i(vcpu,r3,bits(r2,2,7)); +} + + +IA64FAULT vmx_emul_thash(VCPU *vcpu, INST64 inst) +{ + u64 r1,r3; + ISR visr; + IA64_PSR vpsr; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M46.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ +#ifdef CHECK_FAULT + vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); + return IA64_NO_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(unimplemented_gva(vcpu, r3)){ + vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); + return IA64_NO_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_thash(vcpu, r3, &r1); + vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); + return(IA64_NO_FAULT); +} + + +IA64FAULT vmx_emul_ttag(VCPU *vcpu, INST64 inst) +{ + u64 r1,r3; + ISR visr; + IA64_PSR vpsr; + #ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M46.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ +#ifdef CHECK_FAULT + vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); + return IA64_NO_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(unimplemented_gva(vcpu, r3)){ + vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); + return IA64_NO_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_ttag(vcpu, r3, &r1); + vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); + return(IA64_NO_FAULT); +} + + +IA64FAULT vmx_emul_tpa(VCPU *vcpu, INST64 inst) +{ + u64 r1,r3; + ISR visr; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M46.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if(vpsr.cpl!=0){ + visr.val=0; + vcpu_set_isr(vcpu, visr.val); + return IA64_FAULT; + } +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,1); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if (unimplemented_gva(vcpu,r3) ) { + // inject unimplemented_data_address_fault + visr.val = set_isr_ei_ni(vcpu); + visr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + // FAULT_UNIMPLEMENTED_DATA_ADDRESS. + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + + if(vmx_vcpu_tpa(vcpu, r3, &r1)){ + return IA64_FAULT; + } + vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); + return(IA64_NO_FAULT); +} + +IA64FAULT vmx_emul_tak(VCPU *vcpu, INST64 inst) +{ + u64 r1,r3; + ISR visr; + IA64_PSR vpsr; + int fault=IA64_NO_FAULT; +#ifdef CHECK_FAULT + visr.val=0; + if(check_target_register(vcpu, inst.M46.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + vpsr.val=vmx_vcpu_get_psr(vcpu); + if(vpsr.cpl!=0){ + vcpu_set_isr(vcpu, visr.val); + return IA64_FAULT; + } +#endif + if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,1); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif + } + if(vmx_vcpu_tak(vcpu, r3, &r1)){ + return IA64_FAULT; + } + vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); + return(IA64_NO_FAULT); +} + + +/************************************ + * Insert translation register/cache +************************************/ + +IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst) +{ + UINT64 fault, itir, ifa, pte, slot; + ISR isr; + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.ic ) { + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#ifdef VMAL_NO_FAULT_CHECK + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&slot)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&pte)){ +#ifdef VMAL_NO_FAULT_CHECK + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif // VMAL_NO_FAULT_CHECK + } +#ifdef VMAL_NO_FAULT_CHECK + if(is_reserved_rr_register(vcpu, slot)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + + if (vmx_vcpu_get_itir(vcpu,&itir)){ + return(IA64_FAULT); + } + if (vmx_vcpu_get_ifa(vcpu,&ifa)){ + return(IA64_FAULT); + } +#ifdef VMAL_NO_FAULT_CHECK + if (is_reserved_itir_field(vcpu, itir)) { + // TODO + return IA64_FAULT; + } + if (unimplemented_gva(vcpu,ifa) ) { + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + + return (vmx_vcpu_itr_d(vcpu,pte,itir,ifa,slot)); +} + +IA64FAULT vmx_emul_itr_i(VCPU *vcpu, INST64 inst) +{ + UINT64 fault, itir, ifa, pte, slot; + ISR isr; + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.ic ) { + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#ifdef VMAL_NO_FAULT_CHECK + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&slot)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&pte)){ +#ifdef VMAL_NO_FAULT_CHECK + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif // VMAL_NO_FAULT_CHECK + } +#ifdef VMAL_NO_FAULT_CHECK + if(is_reserved_rr_register(vcpu, slot)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + + if (vmx_vcpu_get_itir(vcpu,&itir)){ + return(IA64_FAULT); + } + if (vmx_vcpu_get_ifa(vcpu,&ifa)){ + return(IA64_FAULT); + } +#ifdef VMAL_NO_FAULT_CHECK + if (is_reserved_itir_field(vcpu, itir)) { + // TODO + return IA64_FAULT; + } + if (unimplemented_gva(vcpu,ifa) ) { + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + + return (vmx_vcpu_itr_i(vcpu,pte,itir,ifa,slot)); +} + +IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte) +{ + UINT64 fault; + ISR isr; + IA64_PSR vpsr; + IA64FAULT ret1; + + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.ic ) { + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + +#ifdef VMAL_NO_FAULT_CHECK + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + ret1 = vmx_vcpu_get_gr(vcpu,inst.M45.r2,pte); +#ifdef VMAL_NO_FAULT_CHECK + if( ret1 != IA64_NO_FAULT ){ + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + + if (vmx_vcpu_get_itir(vcpu,itir)){ + return(IA64_FAULT); + } + if (vmx_vcpu_get_ifa(vcpu,ifa)){ + return(IA64_FAULT); + } +#ifdef VMAL_NO_FAULT_CHECK + if (unimplemented_gva(vcpu,ifa) ) { + isr.val = set_isr_ei_ni(vcpu); + isr.code = IA64_RESERVED_REG_FAULT; + vcpu_set_isr(vcpu, isr.val); + unimpl_daddr(vcpu); + return IA64_FAULT; + } +#endif // VMAL_NO_FAULT_CHECK + return IA64_NO_FAULT; +} + +IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst) +{ + UINT64 itir, ifa, pte; + + if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { + return IA64_FAULT; + } + + return (vmx_vcpu_itc_d(vcpu,pte,itir,ifa)); +} + +IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst) +{ + UINT64 itir, ifa, pte; + + if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { + return IA64_FAULT; + } + + return (vmx_vcpu_itc_i(vcpu,pte,itir,ifa)); + +} + +/************************************* + * Moves to semi-privileged registers +*************************************/ + +IA64FAULT vmx_emul_mov_to_ar_imm(VCPU *vcpu, INST64 inst) +{ + // I27 and M30 are identical for these fields + if(inst.M30.ar3!=44){ + panic("Can't support ar register other than itc"); + } +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + UINT64 imm; + if(inst.M30.s){ + imm = -inst.M30.imm; + }else{ + imm = inst.M30.imm; + } + return (vmx_vcpu_set_itc(vcpu, imm)); +} + +IA64FAULT vmx_emul_mov_to_ar_reg(VCPU *vcpu, INST64 inst) +{ + // I26 and M29 are identical for these fields + u64 r2; + if(inst.M29.ar3!=44){ + panic("Can't support ar register other than itc"); + } + if(vmx_vcpu_get_gr(vcpu,inst.M29.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + return (vmx_vcpu_set_itc(vcpu, r2)); +} + + +IA64FAULT vmx_emul_mov_from_ar_reg(VCPU *vcpu, INST64 inst) +{ + // I27 and M30 are identical for these fields + if(inst.M31.ar3!=44){ + panic("Can't support ar register other than itc"); + } +#ifdef CHECK_FAULT + if(check_target_register(vcpu,inst.M31.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.si&& vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + u64 r1; + vmx_vcpu_get_itc(vcpu,&r1); + vmx_vcpu_set_gr(vcpu,inst.M31.r1,r1,0); + return IA64_NO_FAULT; +} + + +/******************************** + * Moves to privileged registers +********************************/ + +IA64FAULT vmx_emul_mov_to_pkr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_pkr(vcpu,r3,r2)); +} + +IA64FAULT vmx_emul_mov_to_rr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_rr(vcpu,r3,r2)); +} + +IA64FAULT vmx_emul_mov_to_dbr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_dbr(vcpu,r3,r2)); +} + +IA64FAULT vmx_emul_mov_to_ibr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_ibr(vcpu,r3,r2)); +} + +IA64FAULT vmx_emul_mov_to_pmc(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_pmc(vcpu,r3,r2)); +} + +IA64FAULT vmx_emul_mov_to_pmd(VCPU *vcpu, INST64 inst) +{ + u64 r3,r2; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } + return (vmx_vcpu_set_pmd(vcpu,r3,r2)); +} + + +/********************************** + * Moves from privileged registers + **********************************/ + +IA64FAULT vmx_emul_mov_from_rr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_rr_register(vcpu,r3>>VRN_SHIFT)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + } +#endif //CHECK_FAULT + vmx_vcpu_get_rr(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_from_pkr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_indirect_register(vcpu,r3)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_get_pkr(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_from_dbr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_indirect_register(vcpu,r3)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_get_dbr(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_from_ibr(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_indirect_register(vcpu,r3)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_get_ibr(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_from_pmc(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if (vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } + +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_indirect_register(vcpu,r3)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_get_pmc(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_from_cpuid(VCPU *vcpu, INST64 inst) +{ + u64 r3,r1; +#ifdef CHECK_FAULT + if(check_target_register(vcpu, inst.M43.r1)){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if(is_reserved_indirect_register(vcpu,r3)){ + set_rsv_reg_field_isr(vcpu); + rsv_reg_field(vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + vmx_vcpu_get_cpuid(vcpu,r3,&r1); + return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); +} + +IA64FAULT vmx_emul_mov_to_cr(VCPU *vcpu, INST64 inst) +{ + u64 r2,cr3; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if(is_reserved_cr(inst.M32.cr3)||(vpsr.ic&&is_interruption_control_cr(inst.M32.cr3))){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + if(vmx_vcpu_get_gr(vcpu, inst.M32.r2, &r2)){ +#ifdef CHECK_FAULT + set_isr_reg_nat_consumption(vcpu,0,0); + rnat_comsumption(vcpu); + return IA64_FAULT; +#endif //CHECK_FAULT + } +#ifdef CHECK_FAULT + if ( check_cr_rsv_fields (inst.M32.cr3, r2)) { + /* Inject Reserved Register/Field fault + * into guest */ + set_rsv_reg_field_isr (vcpu,0); + rsv_reg_field (vcpu); + return IA64_FAULT; + } +#endif //CHECK_FAULT + extern u64 cr_igfld_mask(int index, u64 value); + r2 = cr_igfld_mask(inst.M32.cr3,r2); + VMX_VPD(vcpu, vcr[inst.M32.cr3]) = r2; + switch (inst.M32.cr3) { + case 0: return vmx_vcpu_set_dcr(vcpu,r2); + case 1: return vmx_vcpu_set_itm(vcpu,r2); + case 2: return vmx_vcpu_set_iva(vcpu,r2); + case 8: return vmx_vcpu_set_pta(vcpu,r2); + case 16:return vmx_vcpu_set_ipsr(vcpu,r2); + case 17:return vmx_vcpu_set_isr(vcpu,r2); + case 19:return vmx_vcpu_set_iip(vcpu,r2); + case 20:return vmx_vcpu_set_ifa(vcpu,r2); + case 21:return vmx_vcpu_set_itir(vcpu,r2); + case 22:return vmx_vcpu_set_iipa(vcpu,r2); + case 23:return vmx_vcpu_set_ifs(vcpu,r2); + case 24:return vmx_vcpu_set_iim(vcpu,r2); + case 25:return vmx_vcpu_set_iha(vcpu,r2); + case 64:printk("SET LID to 0x%lx\n", r2); + return vmx_vcpu_set_lid(vcpu,r2); + case 65:return IA64_NO_FAULT; + case 66:return vmx_vcpu_set_tpr(vcpu,r2); + case 67:return vmx_vcpu_set_eoi(vcpu,r2); + case 68:return IA64_NO_FAULT; + case 69:return IA64_NO_FAULT; + case 70:return IA64_NO_FAULT; + case 71:return IA64_NO_FAULT; + case 72:return vmx_vcpu_set_itv(vcpu,r2); + case 73:return vmx_vcpu_set_pmv(vcpu,r2); + case 74:return vmx_vcpu_set_cmcv(vcpu,r2); + case 80:return vmx_vcpu_set_lrr0(vcpu,r2); + case 81:return vmx_vcpu_set_lrr1(vcpu,r2); + default: return IA64_NO_FAULT; + } +} + + +#define cr_get(cr) \ + ((fault=vmx_vcpu_get_##cr(vcpu,&val))==IA64_NO_FAULT)?\ + vmx_vcpu_set_gr(vcpu, tgt, val,0):fault; + + +IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst) +{ + UINT64 tgt = inst.M33.r1; + UINT64 val; + IA64FAULT fault; +#ifdef CHECK_FAULT + IA64_PSR vpsr; + vpsr.val=vmx_vcpu_get_psr(vcpu); + if(is_reserved_cr(inst.M33.cr3)||is_read_only_cr(inst.M33.cr3|| + (vpsr.ic&&is_interruption_control_cr(inst.M33.cr3)))){ + set_illegal_op_isr(vcpu); + illegal_op(vcpu); + return IA64_FAULT; + } + if ( vpsr.cpl != 0) { + /* Inject Privileged Operation fault into guest */ + set_privileged_operation_isr (vcpu, 0); + privilege_op (vcpu); + return IA64_FAULT; + } +#endif // CHECK_FAULT + +// from_cr_cnt[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:val = ia64_getreg(_IA64_REG_CR_LID); +// return vmx_vcpu_set_gr(vcpu,tgt,val,0); + case 64:return cr_get(lid); + case 65: + vmx_vcpu_get_ivr(vcpu,&val); + return vmx_vcpu_set_gr(vcpu,tgt,val,0); + case 66:return cr_get(tpr); + case 67:return vmx_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: + panic("Read reserved cr register"); + } +} + + +static void post_emulation_action(VCPU *vcpu) +{ + if ( vcpu->arch.irq_new_condition ) { + vcpu->arch.irq_new_condition = 0; + vhpi_detection(vcpu); + } +} + +//#define BYPASS_VMAL_OPCODE +extern IA64_SLOT_TYPE slot_types[0x20][3]; +IA64_BUNDLE __vmx_get_domain_bundle(u64 iip) +{ + IA64_BUNDLE bundle; + + fetch_code( current,iip, &bundle.i64[0]); + fetch_code( current,iip+8, &bundle.i64[1]); + return bundle; +} + +/** Emulate a privileged operation. + * + * + * @param vcpu virtual cpu + * @cause the reason cause virtualization fault + * @opcode the instruction code which cause virtualization fault + */ + +void +vmx_emulate(VCPU *vcpu, UINT64 cause, UINT64 opcode) +{ + IA64_BUNDLE bundle; + int slot; + IA64_SLOT_TYPE slot_type; + IA64FAULT status; + INST64 inst; + REGS * regs; + UINT64 iip; + regs = vcpu_regs(vcpu); + iip = regs->cr_iip; + IA64_PSR vpsr; +/* + if (privop_trace) { + static long i = 400; + //if (i > 0) printf("privop @%p\n",iip); + if (i > 0) printf("priv_handle_op: @%p, itc=%lx, itm=%lx\n", + iip,ia64_get_itc(),ia64_get_itm()); + i--; + } +*/ +#ifdef VTLB_DEBUG + check_vtlb_sanity(vmx_vcpu_get_vtlb(vcpu)); + dump_vtlb(vmx_vcpu_get_vtlb(vcpu)); +#endif +#if 0 +if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { + printf ("VMAL decode error: cause - %lx; op - %lx\n", + cause, opcode ); + return; +} +#endif +#ifdef BYPASS_VMAL_OPCODE + // make a local copy of the bundle containing the privop + bundle = __vmx_get_domain_bundle(iip); + slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; + if (!slot) inst.inst = bundle.slot0; + else if (slot == 1) + inst.inst = bundle.slot1a + (bundle.slot1b<<18); + else if (slot == 2) inst.inst = bundle.slot2; + else printf("priv_handle_op: illegal slot: %d\n", slot); + slot_type = slot_types[bundle.template][slot]; + ia64_priv_decoder(slot_type, inst, &cause); + if(cause==0){ + printf("This instruction at 0x%lx slot %d can't be virtualized", iip, slot); + panic("123456\n"); + } +#else + inst.inst=opcode; +#endif /* BYPASS_VMAL_OPCODE */ + + /* + * Switch to actual virtual rid in rr0 and rr4, + * which is required by some tlb related instructions. + */ + prepare_if_physical_mode(vcpu); + + switch(cause) { + case EVENT_RSM: + status=vmx_emul_rsm(vcpu, inst); + break; + case EVENT_SSM: + status=vmx_emul_ssm(vcpu, inst); + break; + case EVENT_MOV_TO_PSR: + status=vmx_emul_mov_to_psr(vcpu, inst); + break; + case EVENT_MOV_FROM_PSR: + status=vmx_emul_mov_from_psr(vcpu, inst); + break; + case EVENT_MOV_FROM_CR: + status=vmx_emul_mov_from_cr(vcpu, inst); + break; + case EVENT_MOV_TO_CR: + status=vmx_emul_mov_to_cr(vcpu, inst); + break; + case EVENT_BSW_0: + status=vmx_emul_bsw0(vcpu, inst); + break; + case EVENT_BSW_1: + status=vmx_emul_bsw1(vcpu, inst); + break; + case EVENT_COVER: + status=vmx_emul_cover(vcpu, inst); + break; + case EVENT_RFI: + status=vmx_emul_rfi(vcpu, inst); + break; + case EVENT_ITR_D: + status=vmx_emul_itr_d(vcpu, inst); + break; + case EVENT_ITR_I: + status=vmx_emul_itr_i(vcpu, inst); + break; + case EVENT_PTR_D: + status=vmx_emul_ptr_d(vcpu, inst); + break; + case EVENT_PTR_I: + status=vmx_emul_ptr_i(vcpu, inst); + break; + case EVENT_ITC_D: + status=vmx_emul_itc_d(vcpu, inst); + break; + case EVENT_ITC_I: + status=vmx_emul_itc_i(vcpu, inst); + break; + case EVENT_PTC_L: + status=vmx_emul_ptc_l(vcpu, inst); + break; + case EVENT_PTC_G: + status=vmx_emul_ptc_g(vcpu, inst); + break; + case EVENT_PTC_GA: + status=vmx_emul_ptc_ga(vcpu, inst); + break; + case EVENT_PTC_E: + status=vmx_emul_ptc_e(vcpu, inst); + break; + case EVENT_MOV_TO_RR: + status=vmx_emul_mov_to_rr(vcpu, inst); + break; + case EVENT_MOV_FROM_RR: + status=vmx_emul_mov_from_rr(vcpu, inst); + break; + case EVENT_THASH: + status=vmx_emul_thash(vcpu, inst); + break; + case EVENT_TTAG: + status=vmx_emul_ttag(vcpu, inst); + break; + case EVENT_TPA: + status=vmx_emul_tpa(vcpu, inst); + break; + case EVENT_TAK: + status=vmx_emul_tak(vcpu, inst); + break; + case EVENT_MOV_TO_AR_IMM: + status=vmx_emul_mov_to_ar_imm(vcpu, inst); + break; + case EVENT_MOV_TO_AR: + status=vmx_emul_mov_to_ar_reg(vcpu, inst); + break; + case EVENT_MOV_FROM_AR: + status=vmx_emul_mov_from_ar_reg(vcpu, inst); + break; + case EVENT_MOV_TO_DBR: + status=vmx_emul_mov_to_dbr(vcpu, inst); + break; + case EVENT_MOV_TO_IBR: + status=vmx_emul_mov_to_ibr(vcpu, inst); + break; + case EVENT_MOV_TO_PMC: + status=vmx_emul_mov_to_pmc(vcpu, inst); + break; + case EVENT_MOV_TO_PMD: + status=vmx_emul_mov_to_pmd(vcpu, inst); + break; + case EVENT_MOV_TO_PKR: + status=vmx_emul_mov_to_pkr(vcpu, inst); + break; + case EVENT_MOV_FROM_DBR: + status=vmx_emul_mov_from_dbr(vcpu, inst); + break; + case EVENT_MOV_FROM_IBR: + status=vmx_emul_mov_from_ibr(vcpu, inst); + break; + case EVENT_MOV_FROM_PMC: + status=vmx_emul_mov_from_pmc(vcpu, inst); + break; + case EVENT_MOV_FROM_PKR: + status=vmx_emul_mov_from_pkr(vcpu, inst); + break; + case EVENT_MOV_FROM_CPUID: + status=vmx_emul_mov_from_cpuid(vcpu, inst); + break; + case EVENT_VMSW: + printf ("Unimplemented instruction %d\n", cause); + status=IA64_FAULT; + break; + default: + printf("unknown cause %d, iip: %lx, ipsr: %lx\n", cause,regs->cr_iip,regs->cr_ipsr); + while(1); + /* For unknown cause, let hardware to re-execute */ + status=IA64_RETRY; + break; +// panic("unknown cause in virtualization intercept"); + }; + +#if 0 + if (status == IA64_FAULT) + panic("Emulation failed with cause %d:\n", cause); +#endif + + if ( status == IA64_NO_FAULT && cause !=EVENT_RFI ) { + vmx_vcpu_increment_iip(vcpu); + } + + recover_if_physical_mode(vcpu); + post_emulation_action (vcpu); +//TODO set_irq_check(v); + return; + +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vmx_vsa.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vmx_vsa.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,84 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_vsa.c: Call PAL virtualization services. + * Copyright (c) 2005, Intel Corporation. + * + * 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. + * + * Arun Sharma <arun.sharma@xxxxxxxxx> + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include <asm/asmmacro.h> + + + .text + +/* + * extern UINT64 ia64_call_vsa(UINT64 proc,UINT64 arg1, UINT64 arg2, + * UINT64 arg3, UINT64 arg4, UINT64 arg5, + * UINT64 arg6, UINT64 arg7); + * + * XXX: The currently defined services use only 4 args at the max. The + * rest are not consumed. + */ +GLOBAL_ENTRY(ia64_call_vsa) + .regstk 4,4,0,0 + +rpsave = loc0 +pfssave = loc1 +psrsave = loc2 +entry = loc3 +hostret = r24 + + alloc pfssave=ar.pfs,4,4,0,0 + mov rpsave=rp + movl entry=@gprel(__vsa_base) +1: mov hostret=ip + mov r25=in1 // copy arguments + mov r26=in2 + mov r27=in3 + mov psrsave=psr + ;; + add entry=entry,gp + tbit.nz p6,p0=psrsave,14 // IA64_PSR_I + tbit.nz p7,p0=psrsave,13 // IA64_PSR_IC + ;; + ld8 entry=[entry] // read entry point + ;; + add hostret=2f-1b,hostret // calculate return address + add entry=entry,in0 + ;; + rsm psr.i | psr.ic + ;; + srlz.d + mov b6=entry + br.cond.sptk b6 // call the service +2: + // Architectural sequence for enabling interrupts if necessary +(p7) ssm psr.ic + ;; +(p7) srlz.d + ;; +(p6) ssm psr.i + ;; + mov rp=rpsave + mov ar.pfs=pfssave + mov r8=r31 + ;; + srlz.d + br.ret.sptk rp + +END(ia64_call_vsa) + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx/vtlb.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/vmx/vtlb.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1094 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vtlb.c: guest virtual tlb handling module. + * Copyright (c) 2004, Intel Corporation. + * + * 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. + * + * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) + * XiaoYan Feng (Fleming Feng) (Fleming.feng@xxxxxxxxx) + */ + +#include <linux/sched.h> +#include <asm/tlb.h> +#include <asm/mm.h> +#include <asm/vmx_mm_def.h> +#include <asm/gcc_intrin.h> +#include <linux/interrupt.h> +#include <asm/vmx_vcpu.h> +#define MAX_CCH_LENGTH 40 + + +static void cch_mem_init(thash_cb_t *hcb) +{ + thash_cch_mem_t *p, *q; + + hcb->cch_freelist = p = hcb->cch_buf; + + for ( q=p+1; (u64)(q + 1) <= (u64)hcb->cch_buf + hcb->cch_sz; + p++, q++ ) { + p->next = q; + } + p->next = NULL; +} + +static thash_data_t *cch_alloc(thash_cb_t *hcb) +{ + thash_cch_mem_t *p; + + if ( (p = hcb->cch_freelist) != NULL ) { + hcb->cch_freelist = p->next; + } + return &(p->data); +} + +static void cch_free(thash_cb_t *hcb, thash_data_t *cch) +{ + thash_cch_mem_t *p = (thash_cch_mem_t*)cch; + + p->next = hcb->cch_freelist; + hcb->cch_freelist = p; +} + +/* + * Check to see if the address rid:va is translated by the TLB + */ +static int __is_translated(thash_data_t *tlb, u64 rid, u64 va, CACHE_LINE_TYPE cl) +{ + u64 size1,sa1,ea1; + + if ( tlb->rid != rid || tlb->cl != cl ) + return 0; + size1 = PSIZE(tlb->ps); + sa1 = tlb->vadr & ~(size1-1); // mask the low address bits + ea1 = sa1 + size1; + + if ( va >= sa1 && (va < ea1 || ea1 == 0) ) + return 1; + else + return 0; +} + +/* + * Only for TLB format. + */ +static int +__is_tlb_overlap(thash_cb_t *hcb,thash_data_t *entry,int rid, char cl, u64 sva, u64 eva) +{ + uint64_t size1,size2,sa1,ea1,ea2; + + if ( entry->invalid || entry->rid != rid || entry->cl != cl ) { + return 0; + } + size1=PSIZE(entry->ps); + sa1 = entry->vadr & ~(size1-1); // mask the low address bits + ea1 = sa1 + size1; + if ( (sva >= ea1 && ea1 != 0) || (eva <= sa1 && eva != 0) ) + return 0; + else + return 1; + +} + +static void __rem_tr (thash_cb_t *hcb, thash_data_t *tr) +{ + if ( hcb->remove_notifier ) { + (hcb->remove_notifier)(hcb,tr); + } + tr->invalid = 1; +} + +static inline void __set_tr (thash_data_t *tr, thash_data_t *data, int idx) +{ + *tr = *data; + tr->tr_idx = idx; +} + + +static void __init_tr(thash_cb_t *hcb) +{ + int i; + thash_data_t *tr; + + for ( i=0, tr = &ITR(hcb,0); i<NITRS; i++ ) { + tr[i].invalid = 1; + } + for ( i=0, tr = &DTR(hcb,0); i<NDTRS; i++ ) { + tr[i].invalid = 1; + } +} + +/* + * Replace TR entry. + */ +static void rep_tr(thash_cb_t *hcb,thash_data_t *insert, int idx) +{ + thash_data_t *tr; + + if ( insert->cl == ISIDE_TLB ) { + tr = &ITR(hcb,idx); + } + else { + tr = &DTR(hcb,idx); + } + if ( !INVALID_TLB(tr) ) { + __rem_tr(hcb, tr); + } + __set_tr (tr, insert, idx); +} + +/* + * remove TR entry. + */ +static void rem_tr(thash_cb_t *hcb,CACHE_LINE_TYPE cl, int idx) +{ + thash_data_t *tr; + + if ( cl == ISIDE_TLB ) { + tr = &ITR(hcb,idx); + } + else { + tr = &DTR(hcb,idx); + } + if ( !INVALID_TLB(tr) ) { + __rem_tr(hcb, tr); + } +} + +/* + * Delete an thash entry in collision chain. + * prev: the previous entry. + * rem: the removed entry. + */ +static void __rem_chain(thash_cb_t *hcb/*, thash_data_t *prev*/, thash_data_t *rem) +{ + //prev->next = rem->next; + if ( hcb->remove_notifier ) { + (hcb->remove_notifier)(hcb,rem); + } + cch_free (hcb, rem); +} + +/* + * Delete an thash entry leading collision chain. + */ +static void __rem_hash_head(thash_cb_t *hcb, thash_data_t *hash) +{ + thash_data_t *next=hash->next; + + if ( hcb->remove_notifier ) { + (hcb->remove_notifier)(hcb,hash); + } + if ( next != NULL ) { + *hash = *next; + cch_free (hcb, next); + } + else { + INVALIDATE_HASH(hcb, hash); + } +} + +thash_data_t *__vtr_lookup(thash_cb_t *hcb, + u64 rid, u64 va, + CACHE_LINE_TYPE cl) +{ + thash_data_t *tr; + int num,i; + + if ( cl == ISIDE_TLB ) { + tr = &ITR(hcb,0); + num = NITRS; + } + else { + tr = &DTR(hcb,0); + num = NDTRS; + } + for ( i=0; i<num; i++ ) { + if ( !INVALID_ENTRY(hcb,&tr[i]) && + __is_translated(&tr[i], rid, va, cl) ) + return &tr[i]; + } + return NULL; +} + + +/* + * Find overlap VHPT entry within current collision chain + * base on internal priv info. + */ +static inline thash_data_t* _vhpt_next_overlap_in_chain(thash_cb_t *hcb) +{ + thash_data_t *cch; + thash_internal_t *priv = &hcb->priv; + + + for (cch=priv->cur_cch; cch; cch = cch->next) { + if ( priv->tag == cch->etag ) { + return cch; + } + } + return NULL; +} + +/* + * Find overlap TLB/VHPT entry within current collision chain + * base on internal priv info. + */ +static thash_data_t *_vtlb_next_overlap_in_chain(thash_cb_t *hcb) +{ + thash_data_t *cch; + thash_internal_t *priv = &hcb->priv; + + /* Find overlap TLB entry */ + for (cch=priv->cur_cch; cch; cch = cch->next) { + if ( ( cch->tc ? priv->s_sect.tc : priv->s_sect.tr ) && + __is_tlb_overlap(hcb, cch, priv->rid, priv->cl, + priv->_curva, priv->_eva) ) { + return cch; + } + } + return NULL; +} + +/* + * Get the machine format of VHPT entry. + * PARAS: + * 1: tlb: means the tlb format hash entry converting to VHPT. + * 2: va means the guest virtual address that must be coverd by + * the translated machine VHPT. + * 3: vhpt: means the machine format VHPT converting from tlb. + * NOTES: + * 1: In case of the machine address is discontiguous, + * "tlb" needs to be covered by several machine VHPT. va + * is used to choice one of them. + * 2: Foreign map is supported in this API. + * RETURN: + * 0/1: means successful or fail. + * + */ +int __tlb_to_vhpt(thash_cb_t *hcb, + thash_data_t *tlb, u64 va, + thash_data_t *vhpt) +{ + u64 pages,mfn; + ia64_rr vrr; + + ASSERT ( hcb->ht == THASH_VHPT ); + vrr = (hcb->get_rr_fn)(hcb->vcpu,va); + pages = PSIZE(vrr.ps) >> PAGE_SHIFT; + mfn = (hcb->vs->get_mfn)(DOMID_SELF,tlb->ppn, pages); + if ( mfn == INVALID_MFN ) return 0; + + // TODO with machine discontinuous address space issue. + vhpt->etag = (hcb->vs->tag_func)( hcb->pta, + tlb->vadr, tlb->rid, tlb->ps); + //vhpt->ti = 0; + vhpt->itir = tlb->itir & ~ITIR_RV_MASK; + vhpt->page_flags = tlb->page_flags & ~PAGE_FLAGS_RV_MASK; + vhpt->ppn = mfn; + vhpt->next = 0; + return 1; +} + + +/* + * Insert an entry to hash table. + * NOTES: + * 1: TLB entry may be TR, TC or Foreign Map. For TR entry, + * itr[]/dtr[] need to be updated too. + * 2: Inserting to collision chain may trigger recycling if + * the buffer for collision chain is empty. + * 3: The new entry is inserted at the next of hash table. + * (I.e. head of the collision chain) + * 4: The buffer holding the entry is allocated internally + * from cch_buf or just in the hash table. + * 5: Return the entry in hash table or collision chain. + * 6: Input parameter, entry, should be in TLB format. + * I.e. Has va, rid, ps... + * 7: This API is invoked by emulating ITC/ITR and tlb_miss. + * + */ + +void thash_tr_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va, int idx) +{ + if ( hcb->ht != THASH_TLB || entry->tc ) { + panic("wrong parameter\n"); + } + entry->vadr = PAGEALIGN(entry->vadr,entry->ps); + entry->ppn = PAGEALIGN(entry->ppn, entry->ps-12); + rep_tr(hcb, entry, idx); + return ; +} + +thash_data_t *__alloc_chain(thash_cb_t *hcb,thash_data_t *entry) +{ + thash_data_t *cch; + + cch = cch_alloc(hcb); + if(cch == NULL){ + // recycle + if ( hcb->recycle_notifier ) { + hcb->recycle_notifier(hcb,(u64)entry); + } + thash_purge_all(hcb); + cch = cch_alloc(hcb); + } + return cch; +} + +/* + * Insert an entry into hash TLB or VHPT. + * NOTES: + * 1: When inserting VHPT to thash, "va" is a must covered + * address by the inserted machine VHPT entry. + * 2: The format of entry is always in TLB. + * 3: The caller need to make sure the new entry will not overlap + * with any existed entry. + */ +void vtlb_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) +{ + thash_data_t *hash_table, *cch; + int flag; + ia64_rr vrr; + u64 gppn; + u64 ppns, ppne; + + hash_table = (hcb->hash_func)(hcb->pta, + va, entry->rid, entry->ps); + if( INVALID_ENTRY(hcb, hash_table) ) { + *hash_table = *entry; + hash_table->next = 0; + } + else { + // TODO: Add collision chain length limitation. + cch = __alloc_chain(hcb,entry); + + *cch = *hash_table; + *hash_table = *entry; + hash_table->next = cch; + } + if(hcb->vcpu->domain->domain_id==0){ + thash_insert(hcb->ts->vhpt, entry, va); + return; + } + flag = 1; + gppn = (POFFSET(va,entry->ps)|PAGEALIGN((entry->ppn<<12),entry->ps))>>PAGE_SHIFT; + ppns = PAGEALIGN((entry->ppn<<12),entry->ps); + ppne = ppns + PSIZE(entry->ps); + if(((ppns<=0xa0000)&&(ppne>0xa0000))||((ppne>0xc0000)&&(ppns<=0xc0000))) + flag = 0; + if((__gpfn_is_mem(hcb->vcpu->domain, gppn)&&flag)) + thash_insert(hcb->ts->vhpt, entry, va); + return ; +} + +static void vhpt_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) +{ + thash_data_t *hash_table, *cch; + ia64_rr vrr; + + hash_table = (hcb->hash_func)(hcb->pta, + va, entry->rid, entry->ps); + if( INVALID_ENTRY(hcb, hash_table) ) { + if ( !__tlb_to_vhpt(hcb, entry, va, hash_table) ) { + panic("Can't convert to machine VHPT entry\n"); + } + hash_table->next = 0; + } + else { + // TODO: Add collision chain length limitation. + cch = __alloc_chain(hcb,entry); + + *cch = *hash_table; + if ( !__tlb_to_vhpt(hcb, entry, va, hash_table) ) { + panic("Can't convert to machine VHPT entry\n"); + } + hash_table->next = cch; + if(hash_table->tag==hash_table->next->tag) + while(1); + } + return /*hash_table*/; +} + +void thash_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) +{ + thash_data_t *hash_table; + ia64_rr vrr; + + vrr = (hcb->get_rr_fn)(hcb->vcpu,entry->vadr); + if ( entry->ps != vrr.ps && entry->tc ) { + panic("Not support for multiple page size now\n"); + } + entry->vadr = PAGEALIGN(entry->vadr,entry->ps); + entry->ppn = PAGEALIGN(entry->ppn, entry->ps-12); + (hcb->ins_hash)(hcb, entry, va); + +} + +static void rem_thash(thash_cb_t *hcb, thash_data_t *entry) +{ + thash_data_t *hash_table, *p, *q; + thash_internal_t *priv = &hcb->priv; + int idx; + + hash_table = priv->hash_base; + if ( hash_table == entry ) { +// if ( PURGABLE_ENTRY(hcb, entry) ) { + __rem_hash_head (hcb, entry); +// } + return ; + } + // remove from collision chain + p = hash_table; + for ( q=p->next; q; q = p->next ) { + if ( q == entry ){ +// if ( PURGABLE_ENTRY(hcb,q ) ) { + p->next = q->next; + __rem_chain(hcb, entry); +// } + return ; + } + p = q; + } + panic("Entry not existed or bad sequence\n"); +} + +static void rem_vtlb(thash_cb_t *hcb, thash_data_t *entry) +{ + thash_data_t *hash_table, *p, *q; + thash_internal_t *priv = &hcb->priv; + int idx; + + if ( !entry->tc ) { + return rem_tr(hcb, entry->cl, entry->tr_idx); + } + rem_thash(hcb, entry); +} + +int cch_depth=0; +/* + * Purge the collision chain starting from cch. + * NOTE: + * For those UN-Purgable entries(FM), this function will return + * the head of left collision chain. + */ +static thash_data_t *thash_rem_cch(thash_cb_t *hcb, thash_data_t *cch) +{ + thash_data_t *next; + + if ( ++cch_depth > MAX_CCH_LENGTH ) { + printf ("cch length > MAX_CCH_LENGTH, exceed the expected length\n"); + while(1); + } + if ( cch -> next ) { + next = thash_rem_cch(hcb, cch->next); + } + else { + next = NULL; + } + if ( PURGABLE_ENTRY(hcb, cch) ) { + __rem_chain(hcb, cch); + return next; + } + else { + cch->next = next; + return cch; + } +} + +/* + * Purge one hash line (include the entry in hash table). + * Can only be called by thash_purge_all. + * Input: + * hash: The head of collision chain (hash table) + * + */ +static void thash_rem_line(thash_cb_t *hcb, thash_data_t *hash) +{ + if ( INVALID_ENTRY(hcb, hash) ) return; + + if ( hash->next ) { + cch_depth = 0; + hash->next = thash_rem_cch(hcb, hash->next); + } + // Then hash table itself. + if ( PURGABLE_ENTRY(hcb, hash) ) { + __rem_hash_head(hcb, hash); + } +} + + +/* + * Find an overlap entry in hash table and its collision chain. + * Refer to SDM2 4.1.1.4 for overlap definition. + * PARAS: + * 1: in: TLB format entry, rid:ps must be same with vrr[]. + * va & ps identify the address space for overlap lookup + * 2: section can be combination of TR, TC and FM. (THASH_SECTION_XX) + * 3: cl means I side or D side. + * RETURNS: + * NULL to indicate the end of findings. + * NOTES: + * + */ +thash_data_t *thash_find_overlap(thash_cb_t *hcb, + thash_data_t *in, search_section_t s_sect) +{ + return (hcb->find_overlap)(hcb, in->vadr, + PSIZE(in->ps), in->rid, in->cl, s_sect); +} + +static thash_data_t *vtlb_find_overlap(thash_cb_t *hcb, + u64 va, u64 size, int rid, char cl, search_section_t s_sect) +{ + thash_data_t *hash_table; + thash_internal_t *priv = &hcb->priv; + u64 tag; + ia64_rr vrr; + + priv->_curva = va & ~(size-1); + priv->_eva = priv->_curva + size; + priv->rid = rid; + vrr = (hcb->get_rr_fn)(hcb->vcpu,va); + priv->ps = vrr.ps; + hash_table = (hcb->hash_func)(hcb->pta, + priv->_curva, rid, priv->ps); + + priv->s_sect = s_sect; + priv->cl = cl; + priv->_tr_idx = 0; + priv->hash_base = hash_table; + priv->cur_cch = hash_table; + return (hcb->next_overlap)(hcb); +} + +static thash_data_t *vhpt_find_overlap(thash_cb_t *hcb, + u64 va, u64 size, int rid, char cl, search_section_t s_sect) +{ + thash_data_t *hash_table; + thash_internal_t *priv = &hcb->priv; + u64 tag; + ia64_rr vrr; + + priv->_curva = va & ~(size-1); + priv->_eva = priv->_curva + size; + priv->rid = rid; + vrr = (hcb->get_rr_fn)(hcb->vcpu,va); + priv->ps = vrr.ps; + hash_table = (hcb->hash_func)( hcb->pta, + priv->_curva, rid, priv->ps); + tag = (hcb->vs->tag_func)( hcb->pta, + priv->_curva, rid, priv->ps); + + priv->tag = tag; + priv->hash_base = hash_table; + priv->cur_cch = hash_table; + return (hcb->next_overlap)(hcb); +} + + +static thash_data_t *vtr_find_next_overlap(thash_cb_t *hcb) +{ + thash_data_t *tr; + thash_internal_t *priv = &hcb->priv; + int num; + + if ( priv->cl == ISIDE_TLB ) { + num = NITRS; + tr = &ITR(hcb,0); + } + else { + num = NDTRS; + tr = &DTR(hcb,0); + } + for (; priv->_tr_idx < num; priv->_tr_idx ++ ) { + if ( __is_tlb_overlap(hcb, &tr[priv->_tr_idx], + priv->rid, priv->cl, + priv->_curva, priv->_eva) ) { + return &tr[priv->_tr_idx++]; + } + } + return NULL; +} + +/* + * Similar with vtlb_next_overlap but find next entry. + * NOTES: + * Intermediate position information is stored in hcb->priv. + */ +static thash_data_t *vtlb_next_overlap(thash_cb_t *hcb) +{ + thash_data_t *ovl; + thash_internal_t *priv = &hcb->priv; + u64 addr,rr_psize; + ia64_rr vrr; + + if ( priv->s_sect.tr ) { + ovl = vtr_find_next_overlap (hcb); + if ( ovl ) return ovl; + priv->s_sect.tr = 0; + } + if ( priv->s_sect.v == 0 ) return NULL; + vrr = (hcb->get_rr_fn)(hcb->vcpu,priv->_curva); + rr_psize = PSIZE(vrr.ps); + + while ( priv->_curva < priv->_eva ) { + if ( !INVALID_ENTRY(hcb, priv->hash_base) ) { + ovl = _vtlb_next_overlap_in_chain(hcb); + if ( ovl ) { + priv->cur_cch = ovl->next; + return ovl; + } + } + priv->_curva += rr_psize; + priv->hash_base = (hcb->hash_func)( hcb->pta, + priv->_curva, priv->rid, priv->ps); + priv->cur_cch = priv->hash_base; + } + return NULL; +} + +static thash_data_t *vhpt_next_overlap(thash_cb_t *hcb) +{ + thash_data_t *ovl; + thash_internal_t *priv = &hcb->priv; + u64 addr,rr_psize; + ia64_rr vrr; + + vrr = (hcb->get_rr_fn)(hcb->vcpu,priv->_curva); + rr_psize = PSIZE(vrr.ps); + + while ( priv->_curva < priv->_eva ) { + if ( !INVALID_ENTRY(hcb, priv->hash_base) ) { + ovl = _vhpt_next_overlap_in_chain(hcb); + if ( ovl ) { + priv->cur_cch = ovl->next; + return ovl; + } + } + priv->_curva += rr_psize; + priv->hash_base = (hcb->hash_func)( hcb->pta, + priv->_curva, priv->rid, priv->ps); + priv->tag = (hcb->vs->tag_func)( hcb->pta, + priv->_curva, priv->rid, priv->ps); + priv->cur_cch = priv->hash_base; + } + return NULL; +} + + +/* + * Find and purge overlap entries in hash table and its collision chain. + * PARAS: + * 1: in: TLB format entry, rid:ps must be same with vrr[]. + * rid, va & ps identify the address space for purge + * 2: section can be combination of TR, TC and FM. (thash_SECTION_XX) + * 3: cl means I side or D side. + * NOTES: + * + */ +void thash_purge_entries(thash_cb_t *hcb, + thash_data_t *in, search_section_t p_sect) +{ + return thash_purge_entries_ex(hcb, in->rid, in->vadr, + in->ps, p_sect, in->cl); +} + +void thash_purge_entries_ex(thash_cb_t *hcb, + u64 rid, u64 va, u64 ps, + search_section_t p_sect, + CACHE_LINE_TYPE cl) +{ + thash_data_t *ovl; + + ovl = (hcb->find_overlap)(hcb, va, PSIZE(ps), rid, cl, p_sect); + while ( ovl != NULL ) { + (hcb->rem_hash)(hcb, ovl); + ovl = (hcb->next_overlap)(hcb); + }; +} + +/* + * Purge overlap TCs and then insert the new entry to emulate itc ops. + * Notes: Only TC entry can purge and insert. + */ +void thash_purge_and_insert(thash_cb_t *hcb, thash_data_t *in) +{ + thash_data_t *ovl; + search_section_t sections; + +#ifdef XEN_DEBUGGER + vrr = (hcb->get_rr_fn)(hcb->vcpu,in->vadr); + if ( in->ps != vrr.ps || hcb->ht != THASH_TLB || !in->tc ) { + panic ("Oops, wrong call for purge_and_insert\n"); + return; + } +#endif + in->vadr = PAGEALIGN(in->vadr,in->ps); + in->ppn = PAGEALIGN(in->ppn, in->ps-12); + sections.tr = 0; + sections.tc = 1; + ovl = (hcb->find_overlap)(hcb, in->vadr, PSIZE(in->ps), + in->rid, in->cl, sections); + if(ovl) + (hcb->rem_hash)(hcb, ovl); +#ifdef XEN_DEBUGGER + ovl = (hcb->next_overlap)(hcb); + if ( ovl ) { + panic ("Oops, 2+ overlaps for purge_and_insert\n"); + return; + } +#endif + (hcb->ins_hash)(hcb, in, in->vadr); +} + +/* + * Purge all TCs or VHPT entries including those in Hash table. + * + */ + +// TODO: add sections. +void thash_purge_all(thash_cb_t *hcb) +{ + thash_data_t *hash_table; + +#ifdef VTLB_DEBUG + extern u64 sanity_check; + static u64 statistics_before_purge_all=0; + if ( statistics_before_purge_all ) { + sanity_check = 1; + check_vtlb_sanity(hcb); + } +#endif + + hash_table = (thash_data_t*)((u64)hcb->hash + hcb->hash_sz); + + for (--hash_table;(u64)hash_table >= (u64)hcb->hash;hash_table--) { + thash_rem_line(hcb, hash_table); + } +} + + +/* + * Lookup the hash table and its collision chain to find an entry + * covering this address rid:va or the entry. + * + * INPUT: + * in: TLB format for both VHPT & TLB. + */ +thash_data_t *vtlb_lookup(thash_cb_t *hcb, + thash_data_t *in) +{ + return vtlb_lookup_ex(hcb, in->rid, in->vadr, in->cl); +} + +thash_data_t *vtlb_lookup_ex(thash_cb_t *hcb, + u64 rid, u64 va, + CACHE_LINE_TYPE cl) +{ + thash_data_t *hash_table, *cch; + u64 tag; + ia64_rr vrr; + + ASSERT ( hcb->ht == THASH_VTLB ); + + cch = __vtr_lookup(hcb, rid, va, cl);; + if ( cch ) return cch; + + vrr = (hcb->get_rr_fn)(hcb->vcpu,va); + hash_table = (hcb->hash_func)( hcb->pta,va, rid, vrr.ps); + + if ( INVALID_ENTRY(hcb, hash_table ) ) + return NULL; + + + for (cch=hash_table; cch; cch = cch->next) { + if ( __is_translated(cch, rid, va, cl) ) + return cch; + } + return NULL; +} + +/* + * Lock/Unlock TC if found. + * NOTES: Only the page in prefered size can be handled. + * return: + * 1: failure + * 0: success + */ +int thash_lock_tc(thash_cb_t *hcb, u64 va, u64 size, int rid, char cl, int lock) +{ + thash_data_t *ovl; + search_section_t sections; + + sections.tr = 1; + sections.tc = 1; + ovl = (hcb->find_overlap)(hcb, va, size, rid, cl, sections); + if ( ovl ) { + if ( !ovl->tc ) { +// panic("Oops, TR for lock\n"); + return 0; + } + else if ( lock ) { + if ( ovl->locked ) { + DPRINTK("Oops, already locked entry\n"); + } + ovl->locked = 1; + } + else if ( !lock ) { + if ( !ovl->locked ) { + DPRINTK("Oops, already unlocked entry\n"); + } + ovl->locked = 0; + } + return 0; + } + return 1; +} + +/* + * Notifier when TLB is deleted from hash table and its collision chain. + * NOTES: + * The typical situation is that TLB remove needs to inform + * VHPT to remove too. + * PARAS: + * 1: hcb is TLB object. + * 2: The format of entry is always in TLB. + * + */ +void tlb_remove_notifier(thash_cb_t *hcb, thash_data_t *entry) +{ + thash_cb_t *vhpt; + search_section_t s_sect; + + s_sect.v = 0; + thash_purge_entries(hcb->ts->vhpt, entry, s_sect); + machine_tlb_purge(entry->rid, entry->vadr, entry->ps); +} + +/* + * Initialize internal control data before service. + */ +void thash_init(thash_cb_t *hcb, u64 sz) +{ + thash_data_t *hash_table; + + cch_mem_init (hcb); + hcb->magic = THASH_CB_MAGIC; + hcb->pta.val = hcb->hash; + hcb->pta.vf = 1; + hcb->pta.ve = 1; + hcb->pta.size = sz; + hcb->get_rr_fn = vmmu_get_rr; + ASSERT ( hcb->hash_sz % sizeof(thash_data_t) == 0 ); + if ( hcb->ht == THASH_TLB ) { + hcb->remove_notifier = tlb_remove_notifier; + hcb->find_overlap = vtlb_find_overlap; + hcb->next_overlap = vtlb_next_overlap; + hcb->rem_hash = rem_vtlb; + hcb->ins_hash = vtlb_insert; + __init_tr(hcb); + } + else { + hcb->remove_notifier = NULL; + hcb->find_overlap = vhpt_find_overlap; + hcb->next_overlap = vhpt_next_overlap; + hcb->rem_hash = rem_thash; + hcb->ins_hash = vhpt_insert; + } + hash_table = (thash_data_t*)((u64)hcb->hash + hcb->hash_sz); + + for (--hash_table;(u64)hash_table >= (u64)hcb->hash;hash_table--) { + INVALIDATE_HASH(hcb,hash_table); + } +} + +#ifdef VTLB_DEBUG +static u64 cch_length_statistics[MAX_CCH_LENGTH+1]; +u64 sanity_check=0; +u64 vtlb_chain_sanity(thash_cb_t *vtlb, thash_cb_t *vhpt, thash_data_t *hash) +{ + thash_data_t *cch; + thash_data_t *ovl; + search_section_t s_sect; + u64 num=0; + + s_sect.v = 0; + for (cch=hash; cch; cch=cch->next) { + ovl = thash_find_overlap(vhpt, cch, s_sect); + while ( ovl != NULL ) { + ovl->checked = 1; + ovl = (vhpt->next_overlap)(vhpt); + }; + num ++; + } + if ( num >= MAX_CCH_LENGTH ) { + cch_length_statistics[MAX_CCH_LENGTH] ++; + } + else { + cch_length_statistics[num] ++; + } + return num; +} + +void check_vtlb_sanity(thash_cb_t *vtlb) +{ +// struct pfn_info *page; + u64 hash_num, i, psr; + static u64 check_ok_num, check_fail_num,check_invalid; +// void *vb1, *vb2; + thash_data_t *hash, *cch; + thash_data_t *ovl; + search_section_t s_sect; + thash_cb_t *vhpt = vtlb->ts->vhpt; + u64 invalid_ratio; + + if ( sanity_check == 0 ) return; + sanity_check --; + s_sect.v = 0; +// page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); +// if ( page == NULL ) { +// panic("No enough contiguous memory for init_domain_mm\n"); +// }; +// vb1 = page_to_virt(page); +// printf("Allocated page=%lp vbase=%lp\n", page, vb1); +// vb2 = vb1 + vtlb->hash_sz; + hash_num = vhpt->hash_sz / sizeof(thash_data_t); +// printf("vb2=%lp, size=%lx hash_num=%lx\n", vb2, vhpt->hash_sz, hash_num); + printf("vtlb=%lp, hash=%lp size=0x%lx; vhpt=%lp, hash=%lp size=0x%lx\n", + vtlb, vtlb->hash,vtlb->hash_sz, + vhpt, vhpt->hash, vhpt->hash_sz); + //memcpy(vb1, vtlb->hash, vtlb->hash_sz); + //memcpy(vb2, vhpt->hash, vhpt->hash_sz); + for ( i=0; i < sizeof(cch_length_statistics)/sizeof(cch_length_statistics[0]); i++ ) { + cch_length_statistics[i] = 0; + } + + local_irq_save(psr); + + hash = vhpt->hash; + for (i=0; i < hash_num; i++) { + if ( !INVALID_ENTRY(vhpt, hash) ) { + for ( cch= hash; cch; cch=cch->next) { + cch->checked = 0; + } + } + hash ++; + } + printf("Done vhpt clear checked flag, hash_num=0x%lx\n", hash_num); + check_invalid = 0; + check_ok_num=0; + hash = vtlb->hash; + for ( i=0; i< hash_num; i++ ) { + if ( !INVALID_ENTRY(vtlb, hash) ) { + check_ok_num += vtlb_chain_sanity(vtlb, vhpt, hash); + } + else { + check_invalid++; + } + hash ++; + } + printf("Done vtlb entry check, hash=%lp\n", hash); + printf("check_ok_num = 0x%lx check_invalid=0x%lx\n", check_ok_num,check_invalid); + invalid_ratio = 1000*check_invalid / hash_num; + printf("%02ld.%01ld%% entries are invalid\n", + invalid_ratio/10, invalid_ratio % 10 ); + for (i=0; i<NDTRS; i++) { + ovl = thash_find_overlap(vhpt, &vtlb->ts->dtr[i], s_sect); + while ( ovl != NULL ) { + ovl->checked = 1; + ovl = (vhpt->next_overlap)(vhpt); + }; + } + printf("Done dTR\n"); + for (i=0; i<NITRS; i++) { + ovl = thash_find_overlap(vhpt, &vtlb->ts->itr[i], s_sect); + while ( ovl != NULL ) { + ovl->checked = 1; + ovl = (vhpt->next_overlap)(vhpt); + }; + } + printf("Done iTR\n"); + check_fail_num = 0; + check_invalid = 0; + check_ok_num=0; + hash = vhpt->hash; + for (i=0; i < hash_num; i++) { + if ( !INVALID_ENTRY(vhpt, hash) ) { + for ( cch= hash; cch; cch=cch->next) { + if ( !cch->checked ) { + printf ("!!!Hash=%lp cch=%lp not within vtlb\n", hash, cch); + check_fail_num ++; + } + else { + check_ok_num++; + } + } + } + else { + check_invalid ++; + } + hash ++; + } + local_irq_restore(psr); + printf("check_ok_num=0x%lx check_fail_num=0x%lx check_invalid=0x%lx\n", + check_ok_num, check_fail_num, check_invalid); + //memcpy(vtlb->hash, vb1, vtlb->hash_sz); + //memcpy(vhpt->hash, vb2, vhpt->hash_sz); + printf("The statistics of collision chain length is listed\n"); + for ( i=0; i < sizeof(cch_length_statistics)/sizeof(cch_length_statistics[0]); i++ ) { + printf("CCH length=%02ld, chain number=%ld\n", i, cch_length_statistics[i]); + } +// free_domheap_pages(page, VCPU_TLB_ORDER); + printf("Done check_vtlb\n"); +} + +void dump_vtlb(thash_cb_t *vtlb) +{ + static u64 dump_vtlb=0; + thash_data_t *hash, *cch, *tr; + u64 hash_num,i; + + if ( dump_vtlb == 0 ) return; + dump_vtlb --; + hash_num = vtlb->hash_sz / sizeof(thash_data_t); + hash = vtlb->hash; + + printf("Dump vTC\n"); + for ( i = 0; i < hash_num; i++ ) { + if ( !INVALID_ENTRY(vtlb, hash) ) { + printf("VTLB at hash=%lp\n", hash); + for (cch=hash; cch; cch=cch->next) { + printf("Entry %lp va=%lx ps=%lx rid=%lx\n", + cch, cch->vadr, cch->ps, cch->rid); + } + } + hash ++; + } + printf("Dump vDTR\n"); + for (i=0; i<NDTRS; i++) { + tr = &DTR(vtlb,i); + printf("Entry %lp va=%lx ps=%lx rid=%lx\n", + tr, tr->vadr, tr->ps, tr->rid); + } + printf("Dump vITR\n"); + for (i=0; i<NITRS; i++) { + tr = &ITR(vtlb,i); + printf("Entry %lp va=%lx ps=%lx rid=%lx\n", + tr, tr->vadr, tr->ps, tr->rid); + } + printf("End of vTLB dump\n"); +} +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/acpi.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/acpi.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,678 @@ +/* + * acpi.c - Architecture-Specific Low-Level ACPI Support + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999,2000 Walt Drummond <drummond@xxxxxxxxxxx> + * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co. + * David Mosberger-Tang <davidm@xxxxxxxxxx> + * Copyright (C) 2000 Intel Corp. + * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@xxxxxxxxx> + * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@xxxxxxxxx> + * Copyright (C) 2001 Jenna Hall <jenna.s.hall@xxxxxxxxx> + * Copyright (C) 2001 Takayoshi Kochi <t-kochi@xxxxxxxxxxxxx> + * Copyright (C) 2002 Erich Focht <efocht@xxxxxxxxxx> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/irq.h> +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/mmzone.h> +#include <asm/io.h> +//#include <asm/iosapic.h> +#include <asm/machvec.h> +#include <asm/page.h> +#include <asm/system.h> +#include <asm/numa.h> +#include <asm/sal.h> +//#include <asm/cyclone.h> + +#define BAD_MADT_ENTRY(entry, end) ( \ + (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ + ((acpi_table_entry_header *)entry)->length != sizeof(*entry)) + +#define PREFIX "ACPI: " + +void (*pm_idle) (void); +EXPORT_SYMBOL(pm_idle); +void (*pm_power_off) (void); + +unsigned char acpi_kbd_controller_present = 1; +unsigned char acpi_legacy_devices; + +const char * +acpi_get_sysname (void) +{ +/* #ifdef CONFIG_IA64_GENERIC */ + unsigned long rsdp_phys; + struct acpi20_table_rsdp *rsdp; + struct acpi_table_xsdt *xsdt; + struct acpi_table_header *hdr; + + rsdp_phys = acpi_find_rsdp(); + if (!rsdp_phys) { + printk(KERN_ERR "ACPI 2.0 RSDP not found, default to \"dig\"\n"); + return "dig"; + } + + rsdp = (struct acpi20_table_rsdp *) __va(rsdp_phys); + if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { + printk(KERN_ERR "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); + return "dig"; + } + + xsdt = (struct acpi_table_xsdt *) __va(rsdp->xsdt_address); + hdr = &xsdt->header; + if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { + printk(KERN_ERR "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); + return "dig"; + } + + if (!strcmp(hdr->oem_id, "HP")) { + return "hpzx1"; + } + else if (!strcmp(hdr->oem_id, "SGI")) { + return "sn2"; + } + + return "dig"; +/* +#else +# if defined (CONFIG_IA64_HP_SIM) + return "hpsim"; +# elif defined (CONFIG_IA64_HP_ZX1) + return "hpzx1"; +# elif defined (CONFIG_IA64_SGI_SN2) + return "sn2"; +# elif defined (CONFIG_IA64_DIG) + return "dig"; +# else +# error Unknown platform. Fix acpi.c. +# endif +#endif +*/ +} + +#ifdef CONFIG_ACPI_BOOT + +#define ACPI_MAX_PLATFORM_INTERRUPTS 256 + +#if 0 +/* Array to record platform interrupt vectors for generic interrupt routing. */ +int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { + [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 +}; + +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC; + +/* + * Interrupt routing API for device drivers. Provides interrupt vector for + * a generic platform event. Currently only CPEI is implemented. + */ +int +acpi_request_vector (u32 int_type) +{ + int vector = -1; + + if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) { + /* corrected platform error interrupt */ + vector = platform_intr_list[int_type]; + } else + printk(KERN_ERR "acpi_request_vector(): invalid interrupt type\n"); + return vector; +} +#endif +char * +__acpi_map_table (unsigned long phys_addr, unsigned long size) +{ + return __va(phys_addr); +} + +/* -------------------------------------------------------------------------- + Boot-time Table Parsing + -------------------------------------------------------------------------- */ + +static int total_cpus __initdata; +static int available_cpus __initdata; +struct acpi_table_madt * acpi_madt __initdata; +static u8 has_8259; + +#if 0 +static int __init +acpi_parse_lapic_addr_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_addr_ovr *lapic; + + lapic = (struct acpi_table_lapic_addr_ovr *) header; + + if (BAD_MADT_ENTRY(lapic, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (lapic->address) { + iounmap((void *) ipi_base_addr); + ipi_base_addr = (unsigned long) ioremap(lapic->address, 0); + } + return 0; +} + + +static int __init +acpi_parse_lsapic (acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lsapic *lsapic; + + lsapic = (struct acpi_table_lsapic *) header; + + if (BAD_MADT_ENTRY(lsapic, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + printk(KERN_INFO "CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid); + + if (!lsapic->flags.enabled) + printk(" disabled"); + else { + printk(" enabled"); +#ifdef CONFIG_SMP + smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; + if (hard_smp_processor_id() + == (unsigned int) smp_boot_data.cpu_phys_id[available_cpus]) + printk(" (BSP)"); +#endif + ++available_cpus; + } + + printk("\n"); + + total_cpus++; + return 0; +} + + +static int __init +acpi_parse_lapic_nmi (acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_nmi *lacpi_nmi; + + lacpi_nmi = (struct acpi_table_lapic_nmi*) header; + + if (BAD_MADT_ENTRY(lacpi_nmi, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support lapic_nmi entries */ + return 0; +} + + +static int __init +acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_iosapic *iosapic; + + iosapic = (struct acpi_table_iosapic *) header; + + if (BAD_MADT_ENTRY(iosapic, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + iosapic_init(iosapic->address, iosapic->global_irq_base); + + return 0; +} + + +static int __init +acpi_parse_plat_int_src ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_plat_int_src *plintsrc; + int vector; + + plintsrc = (struct acpi_table_plat_int_src *) header; + + if (BAD_MADT_ENTRY(plintsrc, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* + * Get vector assignment for this interrupt, set attributes, + * and program the IOSAPIC routing table. + */ + vector = iosapic_register_platform_intr(plintsrc->type, + plintsrc->global_irq, + plintsrc->iosapic_vector, + plintsrc->eid, + plintsrc->id, + (plintsrc->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + (plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + + platform_intr_list[plintsrc->type] = vector; + return 0; +} + + +static int __init +acpi_parse_int_src_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_int_src_ovr *p; + + p = (struct acpi_table_int_src_ovr *) header; + + if (BAD_MADT_ENTRY(p, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + iosapic_override_isa_irq(p->bus_irq, p->global_irq, + (p->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + (p->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + return 0; +} + + +static int __init +acpi_parse_nmi_src (acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_nmi_src *nmi_src; + + nmi_src = (struct acpi_table_nmi_src*) header; + + if (BAD_MADT_ENTRY(nmi_src, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support nimsrc entries */ + return 0; +} +/* Hook from generic ACPI tables.c */ +void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + if (!strncmp(oem_id, "IBM", 3) && + (!strncmp(oem_table_id, "SERMOW", 6))){ + + /* Unfortunatly ITC_DRIFT is not yet part of the + * official SAL spec, so the ITC_DRIFT bit is not + * set by the BIOS on this hardware. + */ + sal_platform_features |= IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT; + + /*Start cyclone clock*/ + cyclone_setup(0); + } +} + +static int __init +acpi_parse_madt (unsigned long phys_addr, unsigned long size) +{ + if (!phys_addr || !size) + return -EINVAL; + + acpi_madt = (struct acpi_table_madt *) __va(phys_addr); + + /* remember the value for reference after free_initmem() */ +#ifdef CONFIG_ITANIUM + has_8259 = 1; /* Firmware on old Itanium systems is broken */ +#else + has_8259 = acpi_madt->flags.pcat_compat; +#endif + iosapic_system_init(has_8259); + + /* Get base address of IPI Message Block */ + + if (acpi_madt->lapic_address) + ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0); + + printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr); + + acpi_madt_oem_check(acpi_madt->header.oem_id, + acpi_madt->header.oem_table_id); + + return 0; +} +#endif + +#ifdef CONFIG_ACPI_NUMA + +#undef SLIT_DEBUG + +#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32) + +static int __initdata srat_num_cpus; /* number of cpus */ +static u32 __initdata pxm_flag[PXM_FLAG_LEN]; +#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag)) +#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag)) +/* maps to convert between proximity domain and logical node ID */ +int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS]; +int __initdata nid_to_pxm_map[MAX_NUMNODES]; +static struct acpi_table_slit __initdata *slit_table; + +/* + * ACPI 2.0 SLIT (System Locality Information Table) + * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf + */ +void __init +acpi_numa_slit_init (struct acpi_table_slit *slit) +{ + u32 len; + + len = sizeof(struct acpi_table_header) + 8 + + slit->localities * slit->localities; + if (slit->header.length != len) { + printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", + len, slit->header.length); + memset(numa_slit, 10, sizeof(numa_slit)); + return; + } + slit_table = slit; +} + +void __init +acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa) +{ + /* record this node in proximity bitmap */ + pxm_bit_set(pa->proximity_domain); + + node_cpuid[srat_num_cpus].phys_id = (pa->apic_id << 8) | (pa->lsapic_eid); + /* nid should be overridden as logical node id later */ + node_cpuid[srat_num_cpus].nid = pa->proximity_domain; + srat_num_cpus++; +} + +void __init +acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma) +{ + unsigned long paddr, size; + u8 pxm; + struct node_memblk_s *p, *q, *pend; + + pxm = ma->proximity_domain; + + /* fill node memory chunk structure */ + paddr = ma->base_addr_hi; + paddr = (paddr << 32) | ma->base_addr_lo; + size = ma->length_hi; + size = (size << 32) | ma->length_lo; + + /* Ignore disabled entries */ + if (!ma->flags.enabled) + return; + + /* record this node in proximity bitmap */ + pxm_bit_set(pxm); + + /* Insertion sort based on base address */ + pend = &node_memblk[num_node_memblks]; + for (p = &node_memblk[0]; p < pend; p++) { + if (paddr < p->start_paddr) + break; + } + if (p < pend) { + for (q = pend - 1; q >= p; q--) + *(q + 1) = *q; + } + p->start_paddr = paddr; + p->size = size; + p->nid = pxm; + num_node_memblks++; +} + +void __init +acpi_numa_arch_fixup (void) +{ + int i, j, node_from, node_to; + + /* If there's no SRAT, fix the phys_id */ + if (srat_num_cpus == 0) { + node_cpuid[0].phys_id = hard_smp_processor_id(); + return; + } + + /* calculate total number of nodes in system from PXM bitmap */ + numnodes = 0; /* init total nodes in system */ + + memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map)); + memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map)); + for (i = 0; i < MAX_PXM_DOMAINS; i++) { + if (pxm_bit_test(i)) { + pxm_to_nid_map[i] = numnodes; + node_set_online(numnodes); + nid_to_pxm_map[numnodes++] = i; + } + } + + /* set logical node id in memory chunk structure */ + for (i = 0; i < num_node_memblks; i++) + node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid]; + + /* assign memory bank numbers for each chunk on each node */ + for (i = 0; i < numnodes; i++) { + int bank; + + bank = 0; + for (j = 0; j < num_node_memblks; j++) + if (node_memblk[j].nid == i) + node_memblk[j].bank = bank++; + } + + /* set logical node id in cpu structure */ + for (i = 0; i < srat_num_cpus; i++) + node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid]; + + printk(KERN_INFO "Number of logical nodes in system = %d\n", numnodes); + printk(KERN_INFO "Number of memory chunks in system = %d\n", num_node_memblks); + + if (!slit_table) return; + memset(numa_slit, -1, sizeof(numa_slit)); + for (i=0; i<slit_table->localities; i++) { + if (!pxm_bit_test(i)) + continue; + node_from = pxm_to_nid_map[i]; + for (j=0; j<slit_table->localities; j++) { + if (!pxm_bit_test(j)) + continue; + node_to = pxm_to_nid_map[j]; + node_distance(node_from, node_to) = + slit_table->entry[i*slit_table->localities + j]; + } + } + +#ifdef SLIT_DEBUG + printk("ACPI 2.0 SLIT locality table:\n"); + for (i = 0; i < numnodes; i++) { + for (j = 0; j < numnodes; j++) + printk("%03d ", node_distance(i,j)); + printk("\n"); + } +#endif +} +#endif /* CONFIG_ACPI_NUMA */ + +#if 0 +unsigned int +acpi_register_gsi (u32 gsi, int polarity, int trigger) +{ + return acpi_register_irq(gsi, polarity, trigger); +} +EXPORT_SYMBOL(acpi_register_gsi); +static int __init +acpi_parse_fadt (unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_header *fadt_header; + struct fadt_descriptor_rev2 *fadt; + + if (!phys_addr || !size) + return -EINVAL; + + fadt_header = (struct acpi_table_header *) __va(phys_addr); + if (fadt_header->revision != 3) + return -ENODEV; /* Only deal with ACPI 2.0 FADT */ + + fadt = (struct fadt_descriptor_rev2 *) fadt_header; + + if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER)) + acpi_kbd_controller_present = 0; + + if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES) + acpi_legacy_devices = 1; + + acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE); + return 0; +} +#endif + +unsigned long __init +acpi_find_rsdp (void) +{ + unsigned long rsdp_phys = 0; + + if (efi.acpi20) + rsdp_phys = __pa(efi.acpi20); + else if (efi.acpi) + printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n"); + return rsdp_phys; +} + +#if 0 +int __init +acpi_boot_init (void) +{ + + /* + * MADT + * ---- + * Parse the Multiple APIC Description Table (MADT), if exists. + * Note that this table provides platform SMP configuration + * information -- the successor to MPS tables. + */ + + if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) { + printk(KERN_ERR PREFIX "Can't find MADT\n"); + goto skip_madt; + } + + /* Local APIC */ + + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) + printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) < 1) + printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); + + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) < 0) + printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); + + /* I/O APIC */ + + if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) + printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); + + /* System-Level Interrupt Routing */ + + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) + printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) + printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) + printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); + skip_madt: + + /* + * FADT says whether a legacy keyboard controller is present. + * The FADT also contains an SCI_INT line, by which the system + * gets interrupts such as power and sleep buttons. If it's not + * on a Legacy interrupt, it needs to be setup. + */ + if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1) + printk(KERN_ERR PREFIX "Can't find FADT\n"); + +#ifdef CONFIG_SMP + if (available_cpus == 0) { + printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n"); + printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id()); + smp_boot_data.cpu_phys_id[available_cpus] = hard_smp_processor_id(); + available_cpus = 1; /* We've got at least one of these, no? */ + } + smp_boot_data.cpu_count = available_cpus; + + smp_build_cpu_map(); +# ifdef CONFIG_ACPI_NUMA + if (srat_num_cpus == 0) { + int cpu, i = 1; + for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++) + if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id()) + node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu]; + } + build_cpu_to_node_map(); +# endif +#endif + /* Make boot-up look pretty */ + printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus); + return 0; +} +int +acpi_gsi_to_irq (u32 gsi, unsigned int *irq) +{ + int vector; + + if (has_8259 && gsi < 16) + *irq = isa_irq_to_vector(gsi); + else { + vector = gsi_to_vector(gsi); + if (vector == -1) + return -1; + + *irq = vector; + } + return 0; +} + +int +acpi_register_irq (u32 gsi, u32 polarity, u32 trigger) +{ + if (has_8259 && gsi < 16) + return isa_irq_to_vector(gsi); + + return iosapic_register_intr(gsi, + (polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + (trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); +} +EXPORT_SYMBOL(acpi_register_irq); +#endif +#endif /* CONFIG_ACPI_BOOT */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/dom0_ops.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/dom0_ops.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,237 @@ +/****************************************************************************** + * Arch-specific dom0_ops.c + * + * Process command requests from domain-0 guest OS. + * + * Copyright (c) 2002, K A Fraser + */ + +#include <xen/config.h> +#include <xen/types.h> +#include <xen/lib.h> +#include <xen/mm.h> +#include <public/dom0_ops.h> +#include <xen/sched.h> +#include <xen/event.h> +#include <asm/pdb.h> +#include <xen/trace.h> +#include <xen/console.h> +#include <public/sched_ctl.h> + +long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) +{ + long ret = 0; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + switch ( op->cmd ) + { + case DOM0_GETPAGEFRAMEINFO: + { + struct pfn_info *page; + unsigned long pfn = op->u.getpageframeinfo.pfn; + domid_t dom = op->u.getpageframeinfo.domain; + struct domain *d; + + ret = -EINVAL; + + if ( unlikely(pfn >= max_page) || + unlikely((d = find_domain_by_id(dom)) == NULL) ) + break; + + page = &frame_table[pfn]; + + if ( likely(get_page(page, d)) ) + { + ret = 0; + + op->u.getpageframeinfo.type = NOTAB; + + if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) + { + switch ( page->u.inuse.type_info & PGT_type_mask ) + { + default: + panic("No such page type\n"); + break; + } + } + + put_page(page); + } + + put_domain(d); + + copy_to_user(u_dom0_op, op, sizeof(*op)); + } + break; + + case DOM0_GETPAGEFRAMEINFO2: + { +#define GPF2_BATCH 128 + int n,j; + int num = op->u.getpageframeinfo2.num; + domid_t dom = op->u.getpageframeinfo2.domain; + unsigned long *s_ptr = (unsigned long*) op->u.getpageframeinfo2.array; + struct domain *d; + unsigned long *l_arr; + ret = -ESRCH; + + if ( unlikely((d = find_domain_by_id(dom)) == NULL) ) + break; + + if ( unlikely(num > 1024) ) + { + ret = -E2BIG; + break; + } + + l_arr = (unsigned long *)alloc_xenheap_page(); + + ret = 0; + for( n = 0; n < num; ) + { + int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n); + + if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) ) + { + ret = -EINVAL; + break; + } + + for( j = 0; j < k; j++ ) + { + struct pfn_info *page; + unsigned long mfn = l_arr[j]; + + if ( unlikely(mfn >= max_page) ) + goto e2_err; + + page = &frame_table[mfn]; + + if ( likely(get_page(page, d)) ) + { + unsigned long type = 0; + + switch( page->u.inuse.type_info & PGT_type_mask ) + { + default: + panic("No such page type\n"); + break; + } + + if ( page->u.inuse.type_info & PGT_pinned ) + type |= LPINTAB; + l_arr[j] |= type; + put_page(page); + } + else + { + e2_err: + l_arr[j] |= XTAB; + } + + } + + if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) ) + { + ret = -EINVAL; + break; + } + + n += j; + } + + free_xenheap_page((unsigned long)l_arr); + + put_domain(d); + } + break; +#ifndef CONFIG_VTI + /* + * NOTE: DOM0_GETMEMLIST has somewhat different semantics on IA64 - + * it actually allocates and maps pages. + */ + case DOM0_GETMEMLIST: + { + unsigned long i; + struct domain *d = find_domain_by_id(op->u.getmemlist.domain); + unsigned long start_page = op->u.getmemlist.max_pfns >> 32; + unsigned long nr_pages = op->u.getmemlist.max_pfns & 0xffffffff; + unsigned long pfn; + unsigned long *buffer = op->u.getmemlist.buffer; + struct page *page; + + ret = -EINVAL; + if ( d != NULL ) + { + ret = 0; + + for ( i = start_page; i < (start_page + nr_pages); i++ ) + { + page = map_new_domain_page(d, i << PAGE_SHIFT); + if ( page == NULL ) + { + ret = -ENOMEM; + break; + } + pfn = page_to_pfn(page); + if ( put_user(pfn, buffer) ) + { + ret = -EFAULT; + break; + } + buffer++; + } + + op->u.getmemlist.num_pfns = i - start_page; + copy_to_user(u_dom0_op, op, sizeof(*op)); + + put_domain(d); + } + } + break; +#else + case DOM0_GETMEMLIST: + { + int i; + struct domain *d = find_domain_by_id(op->u.getmemlist.domain); + unsigned long max_pfns = op->u.getmemlist.max_pfns; + unsigned long pfn; + unsigned long *buffer = op->u.getmemlist.buffer; + struct list_head *list_ent; + + ret = -EINVAL; + if (!d) { + ret = 0; + + spin_lock(&d->page_alloc_lock); + list_ent = d->page_list.next; + for (i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++) { + pfn = list_entry(list_ent, struct pfn_info, list) - + frame_table; + if (put_user(pfn, buffer)) { + ret = -EFAULT; + break; + } + buffer++; + list_ent = frame_table[pfn].list.next; + } + spin_unlock(&d->page_alloc_lock); + + op->u.getmemlist.num_pfns = i; + copy_to_user(u_dom0_op, op, sizeof(*op)); + + put_domain(d); + } + } + break; +#endif // CONFIG_VTI + default: + ret = -ENOSYS; + + } + + return ret; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/dom_fw.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/dom_fw.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,688 @@ +/* + * Xen domain firmware emulation support + * Copyright (C) 2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <xen/config.h> +#include <asm/system.h> +#include <asm/pgalloc.h> + +#include <linux/efi.h> +#include <asm/io.h> +#include <asm/pal.h> +#include <asm/sal.h> +#include <xen/acpi.h> + +#include <asm/dom_fw.h> + +struct ia64_boot_param *dom_fw_init(struct domain *, char *,int,char *,int); +extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); +extern struct domain *dom0; +extern unsigned long dom0_start; + +extern unsigned long running_on_sim; + + +unsigned long dom_fw_base_mpa = -1; +unsigned long imva_fw_base = -1; + +// return domain (meta)physical address for a given imva +// this function is a call-back from dom_fw_init +unsigned long dom_pa(unsigned long imva) +{ + if (dom_fw_base_mpa == -1 || imva_fw_base == -1) { + printf("dom_pa: uninitialized! (spinning...)\n"); + while(1); + } + if (imva - imva_fw_base > PAGE_SIZE) { + printf("dom_pa: bad offset! imva=%p, imva_fw_base=%p (spinning...)\n",imva,imva_fw_base); + while(1); + } + return dom_fw_base_mpa + (imva - imva_fw_base); +} + +// builds a hypercall bundle at domain physical address +void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall) +{ + unsigned long imva; + + if (d == dom0) paddr += dom0_start; + imva = domain_mpa_to_imva(d,paddr); + build_hypercall_bundle(imva,d->arch.breakimm,hypercall,1); +} + + +// builds a hypercall bundle at domain physical address +void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret) +{ + unsigned long imva; + + if (d == dom0) paddr += dom0_start; + imva = domain_mpa_to_imva(d,paddr); + build_hypercall_bundle(imva,d->arch.breakimm,hypercall,ret); +} + + +// FIXME: This is really a hack: Forcing the boot parameter block +// at domain mpaddr 0 page, then grabbing only the low bits of the +// Xen imva, which is the offset into the page +unsigned long dom_fw_setup(struct domain *d, char *args, int arglen) +{ + struct ia64_boot_param *bp; + + dom_fw_base_mpa = 0; + if (d == dom0) dom_fw_base_mpa += dom0_start; + imva_fw_base = domain_mpa_to_imva(d,dom_fw_base_mpa); + bp = dom_fw_init(d,args,arglen,imva_fw_base,PAGE_SIZE); + return dom_pa((unsigned long)bp); +} + + +/* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */ + +#define MB (1024*1024UL) + +#define NUM_EFI_SYS_TABLES 6 +#define PASS_THRU_IOPORT_SPACE +#ifdef PASS_THRU_IOPORT_SPACE +# define NUM_MEM_DESCS 4 +#else +# define NUM_MEM_DESCS 3 +#endif + + +#define SECS_PER_HOUR (60 * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +/* Compute the `struct tm' representation of *T, + offset OFFSET seconds east of UTC, + and store year, yday, mon, mday, wday, hour, min, sec into *TP. + Return nonzero if successful. */ +int +offtime (unsigned long t, efi_time_t *tp) +{ + const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y; + const unsigned short int *ip; + + days = t / SECS_PER_DAY; + rem = t % SECS_PER_DAY; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + tp->hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tp->minute = rem / 60; + tp->second = rem % 60; + /* January 1, 1970 was a Thursday. */ + y = 1970; + +# define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +# define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +# define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + tp->year = y; + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + tp->month = y + 1; + tp->day = days + 1; + return 1; +} + +extern struct ia64_pal_retval pal_emulator_static (unsigned long); + +/* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ + +#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) + +#define REG_OFFSET(addr) (0x00000000000000FF & (addr)) +#define DEVICE_FUNCTION(addr) (0x000000000000FF00 & (addr)) +#define BUS_NUMBER(addr) (0x0000000000FF0000 & (addr)) + +#ifndef XEN +static efi_status_t +fw_efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) +{ +#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) + struct { + int tv_sec; /* must be 32bits to work */ + int tv_usec; + } tv32bits; + + ssc((unsigned long) &tv32bits, 0, 0, 0, SSC_GET_TOD); + + memset(tm, 0, sizeof(*tm)); + offtime(tv32bits.tv_sec, tm); + + if (tc) + memset(tc, 0, sizeof(*tc)); +#else +# error Not implemented yet... +#endif + return EFI_SUCCESS; +} + +static void +efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) +{ +#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) + ssc(status, 0, 0, 0, SSC_EXIT); +#else +# error Not implemented yet... +#endif +} + +static efi_status_t +efi_unimplemented (void) +{ + return EFI_UNSUPPORTED; +} +#endif /* !XEN */ + +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) +{ + long r9 = 0; + long r10 = 0; + long r11 = 0; + long status; + + /* + * Don't do a "switch" here since that gives us code that + * isn't self-relocatable. + */ + status = 0; + if (index == SAL_FREQ_BASE) { + if (!running_on_sim) + status = ia64_sal_freq_base(in1,&r9,&r10); + else switch (in1) { + case SAL_FREQ_BASE_PLATFORM: + r9 = 200000000; + break; + + case SAL_FREQ_BASE_INTERVAL_TIMER: + r9 = 700000000; + break; + + case SAL_FREQ_BASE_REALTIME_CLOCK: + r9 = 1; + break; + + default: + status = -1; + break; + } + } else if (index == SAL_PCI_CONFIG_READ) { + if (current->domain == dom0) { + u64 value; + // note that args 2&3 are swapped!! + status = ia64_sal_pci_config_read(in1,in3,in2,&value); + r9 = value; + } + else printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n"); + } else if (index == SAL_PCI_CONFIG_WRITE) { + if (current->domain == dom0) { + if (((in1 & ~0xffffffffUL) && (in4 == 0)) || + (in4 > 1) || + (in2 > 8) || (in2 & (in2-1))) + printf("*** SAL_PCI_CONF_WRITE?!?(adr=%p,typ=%p,sz=%p,val=%p)\n",in1,in4,in2,in3); + // note that args are in a different order!! + status = ia64_sal_pci_config_write(in1,in4,in2,in3); + } + else printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); + } else if (index == SAL_SET_VECTORS) { + printf("*** CALLED SAL_SET_VECTORS. IGNORED...\n"); + } else if (index == SAL_GET_STATE_INFO) { + printf("*** CALLED SAL_GET_STATE_INFO. IGNORED...\n"); + } else if (index == SAL_GET_STATE_INFO_SIZE) { + printf("*** CALLED SAL_GET_STATE_INFO_SIZE. IGNORED...\n"); + } else if (index == SAL_CLEAR_STATE_INFO) { + printf("*** CALLED SAL_CLEAR_STATE_INFO. IGNORED...\n"); + } else if (index == SAL_MC_RENDEZ) { + printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); + } else if (index == SAL_MC_SET_PARAMS) { + printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); + } else if (index == SAL_CACHE_FLUSH) { + printf("*** CALLED SAL_CACHE_FLUSH. IGNORED...\n"); + } else if (index == SAL_CACHE_INIT) { + printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n"); + } else if (index == SAL_UPDATE_PAL) { + printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n"); + } else { + printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n"); + status = -1; + } + return ((struct sal_ret_values) {status, r9, r10, r11}); +} + +struct ia64_pal_retval +xen_pal_emulator(unsigned long index, unsigned long in1, + unsigned long in2, unsigned long in3) +{ + long r9 = 0; + long r10 = 0; + long r11 = 0; + long status = -1; + +#define USE_PAL_EMULATOR +#ifdef USE_PAL_EMULATOR + return pal_emulator_static(index); +#endif + if (running_on_sim) return pal_emulator_static(index); + if (index >= PAL_COPY_PAL) { + printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", + index); + } + else switch (index) { + case PAL_MEM_ATTRIB: + status = ia64_pal_mem_attrib(&r9); + break; + case PAL_FREQ_BASE: + status = ia64_pal_freq_base(&r9); + break; + case PAL_PROC_GET_FEATURES: + status = ia64_pal_proc_get_features(&r9,&r10,&r11); + break; + case PAL_BUS_GET_FEATURES: + status = ia64_pal_bus_get_features(&r9,&r10,&r11); + break; + case PAL_FREQ_RATIOS: + status = ia64_pal_freq_ratios(&r9,&r10,&r11); + break; + case PAL_PTCE_INFO: + { + // return hard-coded xen-specific values because ptc.e + // is emulated on xen to always flush everything + // these values result in only one ptc.e instruction + status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0; + } + break; + case PAL_VERSION: + status = ia64_pal_version(&r9,&r10); + break; + case PAL_VM_PAGE_SIZE: + status = ia64_pal_vm_page_size(&r9,&r10); + break; + case PAL_DEBUG_INFO: + status = ia64_pal_debug_info(&r9,&r10); + break; + case PAL_CACHE_SUMMARY: + status = ia64_pal_cache_summary(&r9,&r10); + break; + case PAL_VM_SUMMARY: + // FIXME: what should xen return for these, figure out later + // For now, linux does the right thing if pal call fails + // In particular, rid_size must be set properly! + //status = ia64_pal_vm_summary(&r9,&r10); + break; + case PAL_RSE_INFO: + status = ia64_pal_rse_info(&r9,&r10); + break; + case PAL_VM_INFO: + status = ia64_pal_vm_info(in1,in2,&r9,&r10); + break; + case PAL_REGISTER_INFO: + status = ia64_pal_register_info(in1,&r9,&r10); + break; + case PAL_CACHE_FLUSH: + /* FIXME */ + printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); + BUG(); + break; + case PAL_PERF_MON_INFO: + { + unsigned long pm_buffer[16]; + int i; + status = ia64_pal_perf_mon_info(pm_buffer,&r9); + if (status != 0) { + while(1) + printk("PAL_PERF_MON_INFO fails ret=%d\n",status); + break; + } + if (copy_to_user((void __user *)in1,pm_buffer,128)) { + while(1) + printk("xen_pal_emulator: PAL_PERF_MON_INFO " + "can't copy to user!!!!\n"); + status = -1; + break; + } + } + break; + case PAL_CACHE_INFO: + { + pal_cache_config_info_t ci; + status = ia64_pal_cache_config_info(in1,in2,&ci); + if (status != 0) break; + r9 = ci.pcci_info_1.pcci1_data; + r10 = ci.pcci_info_2.pcci2_data; + } + break; + case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ + printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n"); + break; + case PAL_HALT_INFO: /* inappropriate info for guest? */ + printk("PAL_HALT_INFO NOT IMPLEMENTED, IGNORED!\n"); + break; + default: + printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", + index); + break; + } + return ((struct ia64_pal_retval) {status, r9, r10, r11}); +} + +#define NFUNCPTRS 20 + +void print_md(efi_memory_desc_t *md) +{ +#if 1 + printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", + md->type, md->attribute, md->phys_addr, + md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), + md->num_pages >> (20 - EFI_PAGE_SHIFT)); +#endif +} + +#define LSAPIC_NUM 16 // TEMP +static u32 lsapic_flag=1; + +/* Provide only one LP to guest */ +static int +acpi_update_lsapic (acpi_table_entry_header *header) +{ + struct acpi_table_lsapic *lsapic; + + lsapic = (struct acpi_table_lsapic *) header; + if (!lsapic) + return -EINVAL; + + if (lsapic->flags.enabled && lsapic_flag) { + printk("enable lsapic entry: 0x%lx\n", (u64)lsapic); + lsapic_flag = 0; /* disable all the following processros */ + } else if (lsapic->flags.enabled) { + printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic); + lsapic->flags.enabled = 0; + } else + printk("lsapic entry is already disabled: 0x%lx\n", (u64)lsapic); + + return 0; +} + +static int +acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size) +{ + u8 checksum=0; + u8* ptr; + int len; + struct acpi_table_madt* acpi_madt; + + if (!phys_addr || !size) + return -EINVAL; + + acpi_madt = (struct acpi_table_madt *) __va(phys_addr); + acpi_madt->header.checksum=0; + + /* re-calculate MADT checksum */ + ptr = (u8*)acpi_madt; + len = acpi_madt->header.length; + while (len>0){ + checksum = (u8)( checksum + (*ptr++) ); + len--; + } + acpi_madt->header.checksum = 0x0 - checksum; + + return 0; +} + +/* base is physical address of acpi table */ +void touch_acpi_table(void) +{ + u64 count = 0; + count = acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, NR_CPUS); + if ( count < 1) + printk("Error parsing MADT - no LAPIC entires\n"); + printk("Total %d lsapic entry\n", count); + acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum); + + return; +} + + +struct ia64_boot_param * +dom_fw_init (struct domain *d, char *args, int arglen, char *fw_mem, int fw_mem_size) +{ + efi_system_table_t *efi_systab; + efi_runtime_services_t *efi_runtime; + efi_config_table_t *efi_tables; + struct ia64_sal_systab *sal_systab; + efi_memory_desc_t *efi_memmap, *md; + unsigned long *pal_desc, *sal_desc; + struct ia64_sal_desc_entry_point *sal_ed; + struct ia64_boot_param *bp; + unsigned long *pfn; + unsigned char checksum = 0; + char *cp, *cmd_line, *fw_vendor; + int i = 0; + unsigned long maxmem = d->max_pages * PAGE_SIZE; + unsigned long start_mpaddr = ((d==dom0)?dom0_start:0); + +# define MAKE_MD(typ, attr, start, end, abs) \ + do { \ + md = efi_memmap + i++; \ + md->type = typ; \ + md->pad = 0; \ + md->phys_addr = abs ? start : start_mpaddr + start; \ + md->virt_addr = 0; \ + md->num_pages = (end - start) >> 12; \ + md->attribute = attr; \ + print_md(md); \ + } while (0) + +/* FIXME: should check size but for now we have a whole MB to play with. + And if stealing code from fw-emu.c, watch out for new fw_vendor on the end! + if (fw_mem_size < sizeof(fw_mem_proto)) { + printf("sys_fw_init: insufficient space for fw_mem\n"); + return 0; + } +*/ + memset(fw_mem, 0, fw_mem_size); + +#ifdef XEN +#else + pal_desc = (unsigned long *) &pal_emulator_static; + sal_desc = (unsigned long *) &sal_emulator; +#endif + + cp = fw_mem; + efi_systab = (void *) cp; cp += sizeof(*efi_systab); + efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); + efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables); + sal_systab = (void *) cp; cp += sizeof(*sal_systab); + sal_ed = (void *) cp; cp += sizeof(*sal_ed); + efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); + bp = (void *) cp; cp += sizeof(*bp); + pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn); + cmd_line = (void *) cp; + + if (args) { + if (arglen >= 1024) + arglen = 1023; + memcpy(cmd_line, args, arglen); + } else { + arglen = 0; + } + cmd_line[arglen] = '\0'; + + memset(efi_systab, 0, sizeof(efi_systab)); + efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; + efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; + efi_systab->hdr.headersize = sizeof(efi_systab->hdr); + cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary +#define FW_VENDOR "X\0e\0n\0/\0i\0a\0\066\0\064\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary + + memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR)); + efi_systab->fw_vendor = dom_pa(fw_vendor); + + efi_systab->fw_revision = 1; + efi_systab->runtime = (void *) dom_pa(efi_runtime); + efi_systab->nr_tables = NUM_EFI_SYS_TABLES; + efi_systab->tables = dom_pa(efi_tables); + + efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; + efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; + efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); +#define EFI_HYPERCALL_PATCH(tgt,call) do { \ + dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \ + tgt = dom_pa(pfn); \ + *pfn++ = FW_HYPERCALL_##call##_PADDR + ((d==dom0)?dom0_start:0); \ + *pfn++ = 0; \ + } while (0) + + EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME); + EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME); + EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME); + EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME); + EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP); + EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE); + EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE); + EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE); + EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT); + EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM); + + efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID; + efi_tables[0].table = dom_pa(sal_systab); + for (i = 1; i < NUM_EFI_SYS_TABLES; i++) { + efi_tables[i].guid = NULL_GUID; + efi_tables[i].table = 0; + } + if (d == dom0) { + printf("Domain0 EFI passthrough:"); + i = 1; + if (efi.mps) { + efi_tables[i].guid = MPS_TABLE_GUID; + efi_tables[i].table = __pa(efi.mps); + printf(" MPS=%0xlx",efi_tables[i].table); + i++; + } + + touch_acpi_table(); + + if (efi.acpi20) { + efi_tables[i].guid = ACPI_20_TABLE_GUID; + efi_tables[i].table = __pa(efi.acpi20); + printf(" ACPI 2.0=%0xlx",efi_tables[i].table); + i++; + } + if (efi.acpi) { + efi_tables[i].guid = ACPI_TABLE_GUID; + efi_tables[i].table = __pa(efi.acpi); + printf(" ACPI=%0xlx",efi_tables[i].table); + i++; + } + if (efi.smbios) { + efi_tables[i].guid = SMBIOS_TABLE_GUID; + efi_tables[i].table = __pa(efi.smbios); + printf(" SMBIOS=%0xlx",efi_tables[i].table); + i++; + } + if (efi.hcdp) { + efi_tables[i].guid = HCDP_TABLE_GUID; + efi_tables[i].table = __pa(efi.hcdp); + printf(" HCDP=%0xlx",efi_tables[i].table); + i++; + } + printf("\n"); + } + + /* fill in the SAL system table: */ + memcpy(sal_systab->signature, "SST_", 4); + sal_systab->size = sizeof(*sal_systab); + sal_systab->sal_rev_minor = 1; + sal_systab->sal_rev_major = 0; + sal_systab->entry_count = 1; + + strcpy(sal_systab->oem_id, "Xen/ia64"); + strcpy(sal_systab->product_id, "Xen/ia64"); + + /* fill in an entry point: */ + sal_ed->type = SAL_DESC_ENTRY_POINT; +#define FW_HYPERCALL_PATCH(tgt,call,ret) do { \ + dom_fw_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call,ret); \ + tgt = FW_HYPERCALL_##call##_PADDR + ((d==dom0)?dom0_start:0); \ + } while (0) + FW_HYPERCALL_PATCH(sal_ed->pal_proc,PAL_CALL,0); + FW_HYPERCALL_PATCH(sal_ed->sal_proc,SAL_CALL,1); + sal_ed->gp = 0; // will be ignored + + for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) + checksum += *cp; + + sal_systab->checksum = -checksum; + + /* simulate 1MB free memory at physical address zero */ + i = 0; + MAKE_MD(EFI_BOOT_SERVICES_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0); + /* hypercall patches live here, masquerade as reserved PAL memory */ + MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0); + MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 0); +#ifdef PASS_THRU_IOPORT_SPACE + if (d == dom0 && !running_on_sim) { + /* pass through the I/O port space */ + efi_memory_desc_t *efi_get_io_md(void); + efi_memory_desc_t *ia64_efi_io_md = efi_get_io_md(); + u32 type; + u64 iostart, ioend, ioattr; + + type = ia64_efi_io_md->type; + iostart = ia64_efi_io_md->phys_addr; + ioend = ia64_efi_io_md->phys_addr + + (ia64_efi_io_md->num_pages << 12); + ioattr = ia64_efi_io_md->attribute; + MAKE_MD(type,ioattr,iostart,ioend, 1); + } + else + MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0); +#endif + + bp->efi_systab = dom_pa(fw_mem); + bp->efi_memmap = dom_pa(efi_memmap); + bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); + bp->efi_memdesc_size = sizeof(efi_memory_desc_t); + bp->efi_memdesc_version = 1; + bp->command_line = dom_pa(cmd_line); + bp->console_info.num_cols = 80; + bp->console_info.num_rows = 25; + bp->console_info.orig_x = 0; + bp->console_info.orig_y = 24; + bp->fpswa = 0; + + return bp; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/domain.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/domain.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1103 @@ +/* + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes <gareth@xxxxxxxxxxx>, May 2000 + * + * Copyright (C) 2005 Intel Co + * Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> + * + * 05/04/29 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> Add CONFIG_VTI domain support + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/smp.h> +#include <xen/delay.h> +#include <xen/softirq.h> +#include <xen/mm.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/desc.h> +//#include <asm/mpspec.h> +#include <xen/irq.h> +#include <xen/event.h> +//#include <xen/shadow.h> +#include <xen/console.h> + +#include <xen/elf.h> +//#include <asm/page.h> +#include <asm/pgalloc.h> +#include <asm/dma.h> /* for MAX_DMA_ADDRESS */ + +#include <asm/asm-offsets.h> /* for IA64_THREAD_INFO_SIZE */ + +#include <asm/vcpu.h> /* for function declarations */ +#include <public/arch-ia64.h> +#include <asm/vmx.h> +#include <asm/vmx_vcpu.h> +#include <asm/vmx_vpd.h> +#include <asm/pal.h> +#include <public/io/ioreq.h> + +#define CONFIG_DOMAIN0_CONTIGUOUS +unsigned long dom0_start = -1L; +unsigned long dom0_size = 512*1024*1024; //FIXME: Should be configurable +//FIXME: alignment should be 256MB, lest Linux use a 256MB page size +unsigned long dom0_align = 256*1024*1024; +#ifdef DOMU_BUILD_STAGING +unsigned long domU_staging_size = 32*1024*1024; //FIXME: Should be configurable +unsigned long domU_staging_start; +unsigned long domU_staging_align = 64*1024; +unsigned long *domU_staging_area; +#endif + +// initialized by arch/ia64/setup.c:find_initrd() +unsigned long initrd_start = 0, initrd_end = 0; + +#define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend)) + +//extern int loadelfimage(char *); +extern int readelfimage_base_and_size(char *, unsigned long, + unsigned long *, unsigned long *, unsigned long *); + +unsigned long map_domain_page0(struct domain *); +extern unsigned long dom_fw_setup(struct domain *, char *, int); + +/* this belongs in include/asm, but there doesn't seem to be a suitable place */ +void free_perdomain_pt(struct domain *d) +{ + printf("free_perdomain_pt: not implemented\n"); + //free_page((unsigned long)d->mm.perdomain_pt); +} + +int hlt_counter; + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +static void default_idle(void) +{ + if ( hlt_counter == 0 ) + { + local_irq_disable(); + if ( !softirq_pending(smp_processor_id()) ) + safe_halt(); + //else + local_irq_enable(); + } +} + +void continue_cpu_idle_loop(void) +{ + int cpu = smp_processor_id(); + for ( ; ; ) + { +#ifdef IA64 +// __IRQ_STAT(cpu, idle_timestamp) = jiffies +#else + irq_stat[cpu].idle_timestamp = jiffies; +#endif + while ( !softirq_pending(cpu) ) + default_idle(); + raise_softirq(SCHEDULE_SOFTIRQ); + do_softirq(); + } +} + +void startup_cpu_idle_loop(void) +{ + /* Just some sanity to ensure that the scheduler is set up okay. */ + ASSERT(current->domain == IDLE_DOMAIN_ID); + raise_softirq(SCHEDULE_SOFTIRQ); + do_softirq(); + + /* + * Declares CPU setup done to the boot processor. + * Therefore memory barrier to ensure state is visible. + */ + smp_mb(); +#if 0 +//do we have to ensure the idle task has a shared page so that, for example, +//region registers can be loaded from it. Apparently not... + idle0_task.shared_info = (void *)alloc_xenheap_page(); + memset(idle0_task.shared_info, 0, PAGE_SIZE); + /* pin mapping */ + // FIXME: Does this belong here? Or do only at domain switch time? + { + /* WARNING: following must be inlined to avoid nested fault */ + unsigned long psr = ia64_clear_ic(); + ia64_itr(0x2, IA64_TR_SHARED_INFO, SHAREDINFO_ADDR, + pte_val(pfn_pte(ia64_tpa(idle0_task.shared_info) >> PAGE_SHIFT, PAGE_KERNEL)), + PAGE_SHIFT); + ia64_set_psr(psr); + ia64_srlz_i(); + } +#endif + + continue_cpu_idle_loop(); +} + +struct vcpu *arch_alloc_vcpu_struct(void) +{ + /* Per-vp stack is used here. So we need keep vcpu + * same page as per-vp stack */ + return alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER); +} + +void arch_free_vcpu_struct(struct vcpu *v) +{ + free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); +} + +static void init_switch_stack(struct vcpu *v) +{ + struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; + extern void ia64_ret_from_clone; + + memset(sw, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); + sw->ar_bspstore = (unsigned long)v + IA64_RBS_OFFSET; + sw->b0 = (unsigned long) &ia64_ret_from_clone; + sw->ar_fpsr = FPSR_DEFAULT; + v->arch._thread.ksp = (unsigned long) sw - 16; + // stay on kernel stack because may get interrupts! + // ia64_ret_from_clone (which b0 gets in new_thread) switches + // to user stack + v->arch._thread.on_ustack = 0; + memset(v->arch._thread.fph,0,sizeof(struct ia64_fpreg)*96); +} + +void arch_do_createdomain(struct vcpu *v) +{ + struct domain *d = v->domain; + struct thread_info *ti = alloc_thread_info(v); + + /* Clear thread_info to clear some important fields, like preempt_count */ + memset(ti, 0, sizeof(struct thread_info)); + init_switch_stack(v); + + d->shared_info = (void *)alloc_xenheap_page(); + if (!d->shared_info) { + printk("ERROR/HALTING: CAN'T ALLOC PAGE\n"); + while (1); + } + memset(d->shared_info, 0, PAGE_SIZE); + d->shared_info->vcpu_data[0].arch.privregs = + alloc_xenheap_pages(get_order(sizeof(mapped_regs_t))); + printf("arch_vcpu_info=%p\n", d->shared_info->vcpu_data[0].arch.privregs); + memset(d->shared_info->vcpu_data[0].arch.privregs, 0, PAGE_SIZE); + v->vcpu_info = &(d->shared_info->vcpu_data[0]); + + d->max_pages = (128UL*1024*1024)/PAGE_SIZE; // 128MB default // FIXME + +#ifdef CONFIG_VTI + /* Per-domain vTLB and vhpt implementation. Now vmx domain will stick + * to this solution. Maybe it can be deferred until we know created + * one as vmx domain */ + v->arch.vtlb = init_domain_tlb(v); +#endif + + /* We may also need emulation rid for region4, though it's unlikely + * to see guest issue uncacheable access in metaphysical mode. But + * keep such info here may be more sane. + */ + if (((d->arch.metaphysical_rr0 = allocate_metaphysical_rr()) == -1UL) + || ((d->arch.metaphysical_rr4 = allocate_metaphysical_rr()) == -1UL)) + BUG(); + VCPU(v, metaphysical_mode) = 1; + v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0; + v->arch.metaphysical_rr4 = d->arch.metaphysical_rr4; + v->arch.metaphysical_saved_rr0 = d->arch.metaphysical_rr0; + v->arch.metaphysical_saved_rr4 = d->arch.metaphysical_rr4; +#define DOMAIN_RID_BITS_DEFAULT 18 + if (!allocate_rid_range(d,DOMAIN_RID_BITS_DEFAULT)) // FIXME + BUG(); + v->arch.starting_rid = d->arch.starting_rid; + v->arch.ending_rid = d->arch.ending_rid; + // the following will eventually need to be negotiated dynamically + d->xen_vastart = XEN_START_ADDR; + d->xen_vaend = XEN_END_ADDR; + d->shared_info_va = SHAREDINFO_ADDR; + d->arch.breakimm = 0x1000; + v->arch.breakimm = d->arch.breakimm; + + d->arch.mm = xmalloc(struct mm_struct); + if (unlikely(!d->arch.mm)) { + printk("Can't allocate mm_struct for domain %d\n",d->domain_id); + return -ENOMEM; + } + memset(d->arch.mm, 0, sizeof(*d->arch.mm)); + d->arch.mm->pgd = pgd_alloc(d->arch.mm); + if (unlikely(!d->arch.mm->pgd)) { + printk("Can't allocate pgd for domain %d\n",d->domain_id); + return -ENOMEM; + } +} + +void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) +{ + struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; + + printf("arch_getdomaininfo_ctxt\n"); + c->regs = *regs; + c->vcpu.evtchn_vector = v->vcpu_info->arch.evtchn_vector; +#if 0 + if (c->vcpu.privregs && copy_to_user(c->vcpu.privregs, + v->vcpu_info->arch.privregs, sizeof(mapped_regs_t))) { + printk("Bad ctxt address: 0x%lx\n", c->vcpu.privregs); + return -EFAULT; + } +#endif + + c->shared = v->domain->shared_info->arch; +} + +int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) +{ + struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; + struct domain *d = v->domain; + int i, rc, ret; + unsigned long progress = 0; + + printf("arch_set_info_guest\n"); + if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) + return 0; + + if (c->flags & VGCF_VMX_GUEST) { + if (!vmx_enabled) { + printk("No VMX hardware feature for vmx domain.\n"); + return -EINVAL; + } + + vmx_setup_platform(v, c); + } + + *regs = c->regs; + new_thread(v, regs->cr_iip, 0, 0); + + v->vcpu_info->arch.evtchn_vector = c->vcpu.evtchn_vector; + if ( c->vcpu.privregs && copy_from_user(v->vcpu_info->arch.privregs, + c->vcpu.privregs, sizeof(mapped_regs_t))) { + printk("Bad ctxt address in arch_set_info_guest: 0x%lx\n", c->vcpu.privregs); + return -EFAULT; + } + + v->arch.domain_itm_last = -1L; + d->shared_info->arch = c->shared; + + /* Don't redo final setup */ + set_bit(_VCPUF_initialised, &v->vcpu_flags); + return 0; +} + +void arch_do_boot_vcpu(struct vcpu *v) +{ + struct domain *d = v->domain; + printf("arch_do_boot_vcpu: not implemented\n"); + + d->shared_info->vcpu_data[v->vcpu_id].arch.privregs = + alloc_xenheap_pages(get_order(sizeof(mapped_regs_t))); + printf("arch_vcpu_info=%p\n", d->shared_info->vcpu_data[v->vcpu_id].arch.privregs); + memset(d->shared_info->vcpu_data[v->vcpu_id].arch.privregs, 0, PAGE_SIZE); + return; +} + +void domain_relinquish_resources(struct domain *d) +{ + /* FIXME */ + printf("domain_relinquish_resources: not implemented\n"); +} + +// heavily leveraged from linux/arch/ia64/kernel/process.c:copy_thread() +// and linux/arch/ia64/kernel/process.c:kernel_thread() +void new_thread(struct vcpu *v, + unsigned long start_pc, + unsigned long start_stack, + unsigned long start_info) +{ + struct domain *d = v->domain; + struct pt_regs *regs; + struct ia64_boot_param *bp; + extern char saved_command_line[]; + + +#ifdef CONFIG_DOMAIN0_CONTIGUOUS + if (d == dom0) start_pc += dom0_start; +#endif + + regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; + if (VMX_DOMAIN(v)) { + /* dt/rt/it:1;i/ic:1, si:1, vm/bn:1, ac:1 */ + regs->cr_ipsr = 0x501008826008; /* Need to be expanded as macro */ + } else { + regs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) + | IA64_PSR_BITS_TO_SET | IA64_PSR_BN + & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS); + regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT; // domain runs at PL2 + } + regs->cr_iip = start_pc; + regs->cr_ifs = 1UL << 63; /* or clear? */ + regs->ar_fpsr = FPSR_DEFAULT; + + if (VMX_DOMAIN(v)) { +#ifdef CONFIG_VTI + vmx_init_all_rr(v); + if (d == dom0) + VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); + /* Virtual processor context setup */ + VMX_VPD(v, vpsr) = IA64_PSR_BN; + VPD_CR(v, dcr) = 0; +#endif + } else { + init_all_rr(v); + if (d == dom0) + regs->r28 = dom_fw_setup(d,saved_command_line,256L); + else { + regs->ar_rsc |= (2 << 2); /* force PL2/3 */ + regs->r28 = dom_fw_setup(d,"nomca nosmp xencons=tty0 console=tty0 root=/dev/hda1",256L); //FIXME + } + VCPU(v, banknum) = 1; + VCPU(v, metaphysical_mode) = 1; + d->shared_info->arch.flags = (d == dom0) ? (SIF_INITDOMAIN|SIF_PRIVILEGED|SIF_BLK_BE_DOMAIN|SIF_NET_BE_DOMAIN|SIF_USB_BE_DOMAIN) : 0; + } +} + +static struct page * map_new_domain0_page(unsigned long mpaddr) +{ + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + printk("map_new_domain0_page: bad domain0 mpaddr %p!\n",mpaddr); +printk("map_new_domain0_page: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size); + while(1); + } + return pfn_to_page((mpaddr >> PAGE_SHIFT)); +} + +/* allocate new page for domain and map it to the specified metaphysical addr */ +struct page * map_new_domain_page(struct domain *d, unsigned long mpaddr) +{ + struct mm_struct *mm = d->arch.mm; + struct page *p = (struct page *)0; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; +extern unsigned long vhpt_paddr, vhpt_pend; + + if (!mm->pgd) { + printk("map_new_domain_page: domain pgd must exist!\n"); + return(p); + } + pgd = pgd_offset(mm,mpaddr); + if (pgd_none(*pgd)) + pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); + + pud = pud_offset(pgd, mpaddr); + if (pud_none(*pud)) + pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); + + pmd = pmd_offset(pud, mpaddr); + if (pmd_none(*pmd)) + pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); +// pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); + + pte = pte_offset_map(pmd, mpaddr); + if (pte_none(*pte)) { +#ifdef CONFIG_DOMAIN0_CONTIGUOUS + if (d == dom0) p = map_new_domain0_page(mpaddr); + else +#endif + { + p = alloc_domheap_page(d); + // zero out pages for security reasons + memset(__va(page_to_phys(p)),0,PAGE_SIZE); + } + if (unlikely(!p)) { +printf("map_new_domain_page: Can't alloc!!!! Aaaargh!\n"); + return(p); + } +if (unlikely(page_to_phys(p) > vhpt_paddr && page_to_phys(p) < vhpt_pend)) { + printf("map_new_domain_page: reassigned vhpt page %p!!\n",page_to_phys(p)); +} + set_pte(pte, pfn_pte(page_to_phys(p) >> PAGE_SHIFT, + __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX))); + } + else printk("map_new_domain_page: mpaddr %lx already mapped!\n",mpaddr); + return p; +} + +/* map a physical address to the specified metaphysical addr */ +void map_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr) +{ + struct mm_struct *mm = d->arch.mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + if (!mm->pgd) { + printk("map_domain_page: domain pgd must exist!\n"); + return; + } + pgd = pgd_offset(mm,mpaddr); + if (pgd_none(*pgd)) + pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); + + pud = pud_offset(pgd, mpaddr); + if (pud_none(*pud)) + pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); + + pmd = pmd_offset(pud, mpaddr); + if (pmd_none(*pmd)) + pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); +// pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); + + pte = pte_offset_map(pmd, mpaddr); + if (pte_none(*pte)) { + set_pte(pte, pfn_pte(physaddr >> PAGE_SHIFT, + __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX))); + } + else printk("map_domain_page: mpaddr %lx already mapped!\n",mpaddr); +} + +void mpafoo(unsigned long mpaddr) +{ + extern unsigned long privop_trace; + if (mpaddr == 0x3800) + privop_trace = 1; +} + +unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr) +{ + struct mm_struct *mm = d->arch.mm; + pgd_t *pgd = pgd_offset(mm, mpaddr); + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + +#ifdef CONFIG_DOMAIN0_CONTIGUOUS + if (d == dom0) { + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + //printk("lookup_domain_mpa: bad dom0 mpaddr %p!\n",mpaddr); +//printk("lookup_domain_mpa: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size); + mpafoo(mpaddr); + } + pte_t pteval = pfn_pte(mpaddr >> PAGE_SHIFT, + __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)); + pte = &pteval; + return *(unsigned long *)pte; + } +#endif +tryagain: + if (pgd_present(*pgd)) { + pud = pud_offset(pgd,mpaddr); + if (pud_present(*pud)) { + pmd = pmd_offset(pud,mpaddr); + if (pmd_present(*pmd)) { + pte = pte_offset_map(pmd,mpaddr); + if (pte_present(*pte)) { +//printk("lookup_domain_page: found mapping for %lx, pte=%lx\n",mpaddr,pte_val(*pte)); + return *(unsigned long *)pte; + } + } + } + } + /* if lookup fails and mpaddr is "legal", "create" the page */ + if ((mpaddr >> PAGE_SHIFT) < d->max_pages) { + if (map_new_domain_page(d,mpaddr)) goto tryagain; + } + printk("lookup_domain_mpa: bad mpa %p (> %p\n", + mpaddr,d->max_pages<<PAGE_SHIFT); + mpafoo(mpaddr); + return 0; +} + +// FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE +#ifndef CONFIG_VTI +unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) +{ + unsigned long pte = lookup_domain_mpa(d,mpaddr); + unsigned long imva; + + pte &= _PAGE_PPN_MASK; + imva = __va(pte); + imva |= mpaddr & ~PAGE_MASK; + return(imva); +} +#else // CONFIG_VTI +unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) +{ + unsigned long imva = __gpa_to_mpa(d, mpaddr); + + return __va(imva); +} +#endif // CONFIG_VTI + +// remove following line if not privifying in memory +//#define HAVE_PRIVIFY_MEMORY +#ifndef HAVE_PRIVIFY_MEMORY +#define privify_memory(x,y) do {} while(0) +#endif + +// see arch/x86/xxx/domain_build.c +int elf_sanity_check(Elf_Ehdr *ehdr) +{ + return (IS_ELF(*ehdr)); +} + +static void copy_memory(void *dst, void *src, int size) +{ + int remain; + + if (IS_XEN_ADDRESS(dom0,src)) { + memcpy(dst,src,size); + } + else { + printf("About to call __copy_from_user(%p,%p,%d)\n", + dst,src,size); + while (remain = __copy_from_user(dst,src,size)) { + printf("incomplete user copy, %d remain of %d\n", + remain,size); + dst += size - remain; src += size - remain; + size -= remain; + } + } +} + +void loaddomainelfimage(struct domain *d, unsigned long image_start) +{ + char *elfbase = image_start; + //Elf_Ehdr *ehdr = (Elf_Ehdr *)image_start; + Elf_Ehdr ehdr; + Elf_Phdr phdr; + int h, filesz, memsz, paddr; + unsigned long elfaddr, dom_mpaddr, dom_imva; + struct page *p; + unsigned long pteval; + + copy_memory(&ehdr,image_start,sizeof(Elf_Ehdr)); + for ( h = 0; h < ehdr.e_phnum; h++ ) { + copy_memory(&phdr,elfbase + ehdr.e_phoff + (h*ehdr.e_phentsize), + sizeof(Elf_Phdr)); + //if ( !is_loadable_phdr(phdr) ) + if ((phdr.p_type != PT_LOAD)) { + continue; + } + filesz = phdr.p_filesz; memsz = phdr.p_memsz; + elfaddr = elfbase + phdr.p_offset; + dom_mpaddr = phdr.p_paddr; +//printf("p_offset: %x, size=%x\n",elfaddr,filesz); +#ifdef CONFIG_DOMAIN0_CONTIGUOUS + if (d == dom0) { + if (dom_mpaddr+memsz>dom0_size || dom_mpaddr+filesz>dom0_size) { + printf("Domain0 doesn't fit in allocated space!\n"); + while(1); + } + dom_imva = __va(dom_mpaddr + dom0_start); + copy_memory(dom_imva,elfaddr,filesz); + if (memsz > filesz) memset(dom_imva+filesz,0,memsz-filesz); +//FIXME: This test for code seems to find a lot more than objdump -x does + if (phdr.p_flags & PF_X) privify_memory(dom_imva,filesz); + } + else +#endif + while (memsz > 0) { +#ifdef DOMU_AUTO_RESTART + pteval = lookup_domain_mpa(d,dom_mpaddr); + if (pteval) dom_imva = __va(pteval & _PFN_MASK); + else { printf("loaddomainelfimage: BAD!\n"); while(1); } +#else + p = map_new_domain_page(d,dom_mpaddr); + if (unlikely(!p)) BUG(); + dom_imva = __va(page_to_phys(p)); +#endif + if (filesz > 0) { + if (filesz >= PAGE_SIZE) + copy_memory(dom_imva,elfaddr,PAGE_SIZE); + else { // copy partial page, zero the rest of page + copy_memory(dom_imva,elfaddr,filesz); + memset(dom_imva+filesz,0,PAGE_SIZE-filesz); + } +//FIXME: This test for code seems to find a lot more than objdump -x does + if (phdr.p_flags & PF_X) + privify_memory(dom_imva,PAGE_SIZE); + } + else if (memsz > 0) // always zero out entire page + memset(dom_imva,0,PAGE_SIZE); + memsz -= PAGE_SIZE; filesz -= PAGE_SIZE; + elfaddr += PAGE_SIZE; dom_mpaddr += PAGE_SIZE; + } + } +} + +int +parsedomainelfimage(char *elfbase, unsigned long elfsize, unsigned long *entry) +{ + Elf_Ehdr ehdr; + + copy_memory(&ehdr,elfbase,sizeof(Elf_Ehdr)); + + if ( !elf_sanity_check(&ehdr) ) { + printk("ELF sanity check failed.\n"); + return -EINVAL; + } + + if ( (ehdr.e_phoff + (ehdr.e_phnum * ehdr.e_phentsize)) > elfsize ) + { + printk("ELF program headers extend beyond end of image.\n"); + return -EINVAL; + } + + if ( (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) > elfsize ) + { + printk("ELF section headers extend beyond end of image.\n"); + return -EINVAL; + } + +#if 0 + /* Find the section-header strings table. */ + if ( ehdr.e_shstrndx == SHN_UNDEF ) + { + printk("ELF image has no section-header strings table (shstrtab).\n"); + return -EINVAL; + } +#endif + + *entry = ehdr.e_entry; +printf("parsedomainelfimage: entry point = %p\n",*entry); + + return 0; +} + + +void alloc_dom0(void) +{ +#ifdef CONFIG_DOMAIN0_CONTIGUOUS + if (platform_is_hp_ski()) { + dom0_size = 128*1024*1024; //FIXME: Should be configurable + } + printf("alloc_dom0: starting (initializing %d MB...)\n",dom0_size/(1024*1024)); + + /* FIXME: The first trunk (say 256M) should always be assigned to + * Dom0, since Dom0's physical == machine address for DMA purpose. + * Some old version linux, like 2.4, assumes physical memory existing + * in 2nd 64M space. + */ + dom0_start = alloc_boot_pages( + dom0_size >> PAGE_SHIFT, dom0_align >> PAGE_SHIFT); + dom0_start <<= PAGE_SHIFT; + if (!dom0_start) { + printf("construct_dom0: can't allocate contiguous memory size=%p\n", + dom0_size); + while(1); + } + printf("alloc_dom0: dom0_start=%p\n",dom0_start); +#else + dom0_start = 0; +#endif + +} + +#ifdef DOMU_BUILD_STAGING +void alloc_domU_staging(void) +{ + domU_staging_size = 32*1024*1024; //FIXME: Should be configurable + printf("alloc_domU_staging: starting (initializing %d MB...)\n",domU_staging_size/(1024*1024)); + domU_staging_start = alloc_boot_pages( + domU_staging_size >> PAGE_SHIFT, domU_staging_align >> PAGE_SHIFT); + domU_staging_start <<= PAGE_SHIFT; + if (!domU_staging_size) { + printf("alloc_domU_staging: can't allocate, spinning...\n"); + while(1); + } + else domU_staging_area = (unsigned long *)__va(domU_staging_start); + printf("alloc_domU_staging: domU_staging_area=%p\n",domU_staging_area); + +} + +unsigned long +domU_staging_read_8(unsigned long at) +{ + // no way to return errors so just do it + return domU_staging_area[at>>3]; + +} + +unsigned long +domU_staging_write_32(unsigned long at, unsigned long a, unsigned long b, + unsigned long c, unsigned long d) +{ + if (at + 32 > domU_staging_size) return -1; + if (at & 0x1f) return -1; + at >>= 3; + domU_staging_area[at++] = a; + domU_staging_area[at++] = b; + domU_staging_area[at++] = c; + domU_staging_area[at] = d; + return 0; + +} +#endif + +/* + * Domain 0 has direct access to all devices absolutely. However + * the major point of this stub here, is to allow alloc_dom_mem + * handled with order > 0 request. Dom0 requires that bit set to + * allocate memory for other domains. + */ +void physdev_init_dom0(struct domain *d) +{ + set_bit(_DOMF_physdev_access, &d->domain_flags); +} + +extern unsigned long running_on_sim; +unsigned int vmx_dom0 = 0; +int construct_dom0(struct domain *d, + unsigned long image_start, unsigned long image_len, + unsigned long initrd_start, unsigned long initrd_len, + char *cmdline) +{ + char *dst; + int i, rc; + unsigned long pfn, mfn; + unsigned long nr_pt_pages; + unsigned long count; + unsigned long alloc_start, alloc_end; + struct pfn_info *page = NULL; + start_info_t *si; + struct vcpu *v = d->vcpu[0]; + + struct domain_setup_info dsi; + unsigned long p_start; + unsigned long pkern_start; + unsigned long pkern_entry; + unsigned long pkern_end; + unsigned long ret, progress = 0; + +//printf("construct_dom0: starting\n"); + /* Sanity! */ +#ifndef CLONE_DOMAIN0 + if ( d != dom0 ) + BUG(); + if ( test_bit(_DOMF_constructed, &d->domain_flags) ) + BUG(); +#endif + + memset(&dsi, 0, sizeof(struct domain_setup_info)); + + printk("*** LOADING DOMAIN 0 ***\n"); + + alloc_start = dom0_start; + alloc_end = dom0_start + dom0_size; + d->tot_pages = d->max_pages = dom0_size/PAGE_SIZE; + image_start = __va(ia64_boot_param->initrd_start); + image_len = ia64_boot_param->initrd_size; +//printk("image_start=%lx, image_len=%lx\n",image_start,image_len); +//printk("First word of image: %lx\n",*(unsigned long *)image_start); + +//printf("construct_dom0: about to call parseelfimage\n"); + dsi.image_addr = (unsigned long)image_start; + dsi.image_len = image_len; + rc = parseelfimage(&dsi); + if ( rc != 0 ) + return rc; + +#ifdef CONFIG_VTI + /* Temp workaround */ + if (running_on_sim) + dsi.xen_section_string = (char *)1; + + /* Check whether dom0 is vti domain */ + if ((!vmx_enabled) && !dsi.xen_section_string) { + printk("Lack of hardware support for unmodified vmx dom0\n"); + panic(""); + } + + if (vmx_enabled && !dsi.xen_section_string) { + printk("Dom0 is vmx domain!\n"); + vmx_dom0 = 1; + } +#endif + + p_start = dsi.v_start; + pkern_start = dsi.v_kernstart; + pkern_end = dsi.v_kernend; + pkern_entry = dsi.v_kernentry; + +//printk("p_start=%lx, pkern_start=%lx, pkern_end=%lx, pkern_entry=%lx\n",p_start,pkern_start,pkern_end,pkern_entry); + + if ( (p_start & (PAGE_SIZE-1)) != 0 ) + { + printk("Initial guest OS must load to a page boundary.\n"); + return -EINVAL; + } + + printk("METAPHYSICAL MEMORY ARRANGEMENT:\n" + " Kernel image: %lx->%lx\n" + " Entry address: %lx\n" + " Init. ramdisk: (NOT IMPLEMENTED YET)\n", + pkern_start, pkern_end, pkern_entry); + + if ( (pkern_end - pkern_start) > (d->max_pages * PAGE_SIZE) ) + { + printk("Initial guest OS requires too much space\n" + "(%luMB is greater than %luMB limit)\n", + (pkern_end-pkern_start)>>20, (d->max_pages<<PAGE_SHIFT)>>20); + return -ENOMEM; + } + + // if high 3 bits of pkern start are non-zero, error + + // if pkern end is after end of metaphysical memory, error + // (we should be able to deal with this... later) + + + // + +#if 0 + strcpy(d->name,"Domain0"); +#endif + + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1; + +#ifdef CONFIG_VTI + /* Construct a frame-allocation list for the initial domain, since these + * pages are allocated by boot allocator and pfns are not set properly + */ + for ( mfn = (alloc_start>>PAGE_SHIFT); + mfn < (alloc_end>>PAGE_SHIFT); + mfn++ ) + { + page = &frame_table[mfn]; + page_set_owner(page, d); + page->u.inuse.type_info = 0; + page->count_info = PGC_allocated | 1; + list_add_tail(&page->list, &d->page_list); + + /* Construct 1:1 mapping */ + machine_to_phys_mapping[mfn] = mfn; + } + + /* Dom0's pfn is equal to mfn, so there's no need to allocate pmt + * for dom0 + */ + d->arch.pmt = NULL; +#endif + + /* Copy the OS image. */ + loaddomainelfimage(d,image_start); + + /* Copy the initial ramdisk. */ + //if ( initrd_len != 0 ) + // memcpy((void *)vinitrd_start, initrd_start, initrd_len); + + /* Sync d/i cache conservatively */ + ret = ia64_pal_cache_flush(4, 0, &progress, NULL); + if (ret != PAL_STATUS_SUCCESS) + panic("PAL CACHE FLUSH failed for dom0.\n"); + printk("Sync i/d cache for dom0 image SUCC\n"); + +#if 0 + /* Set up start info area. */ + //si = (start_info_t *)vstartinfo_start; + memset(si, 0, PAGE_SIZE); + si->nr_pages = d->tot_pages; + si->shared_info = virt_to_phys(d->shared_info); + si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN; + //si->pt_base = vpt_start; + //si->nr_pt_frames = nr_pt_pages; + //si->mfn_list = vphysmap_start; + + if ( initrd_len != 0 ) + { + //si->mod_start = vinitrd_start; + si->mod_len = initrd_len; + printk("Initrd len 0x%lx, start at 0x%08lx\n", + si->mod_len, si->mod_start); + } + + dst = si->cmd_line; + if ( cmdline != NULL ) + { + for ( i = 0; i < 255; i++ ) + { + if ( cmdline[i] == '\0' ) + break; + *dst++ = cmdline[i]; + } + } + *dst = '\0'; + + zap_low_mappings(); /* Do the same for the idle page tables. */ +#endif + + /* Give up the VGA console if DOM0 is configured to grab it. */ + if (cmdline != NULL) + console_endboot(strstr(cmdline, "tty0") != NULL); + + /* VMX specific construction for Dom0, if hardware supports VMX + * and Dom0 is unmodified image + */ + printk("Dom0: 0x%lx, domain: 0x%lx\n", (u64)dom0, (u64)d); + if (vmx_dom0) + vmx_final_setup_domain(dom0); + + set_bit(_DOMF_constructed, &d->domain_flags); + + new_thread(v, pkern_entry, 0, 0); + physdev_init_dom0(d); + + // FIXME: Hack for keyboard input +#ifdef CLONE_DOMAIN0 +if (d == dom0) +#endif + serial_input_init(); + if (d == dom0) { + VCPU(v, delivery_mask[0]) = -1L; + VCPU(v, delivery_mask[1]) = -1L; + VCPU(v, delivery_mask[2]) = -1L; + VCPU(v, delivery_mask[3]) = -1L; + } + else __set_bit(0x30, VCPU(v, delivery_mask)); + + return 0; +} + +// FIXME: When dom0 can construct domains, this goes away (or is rewritten) +int construct_domU(struct domain *d, + unsigned long image_start, unsigned long image_len, + unsigned long initrd_start, unsigned long initrd_len, + char *cmdline) +{ + int i, rc; + struct vcpu *v = d->vcpu[0]; + unsigned long pkern_entry; + +#ifndef DOMU_AUTO_RESTART + if ( test_bit(_DOMF_constructed, &d->domain_flags) ) BUG(); +#endif + + printk("*** LOADING DOMAIN %d ***\n",d->domain_id); + + d->max_pages = dom0_size/PAGE_SIZE; // FIXME: use dom0 size + // FIXME: use domain0 command line + rc = parsedomainelfimage(image_start, image_len, &pkern_entry); + printk("parsedomainelfimage returns %d\n",rc); + if ( rc != 0 ) return rc; + + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1; + + /* Copy the OS image. */ + printk("calling loaddomainelfimage(%p,%p)\n",d,image_start); + loaddomainelfimage(d,image_start); + printk("loaddomainelfimage returns\n"); + + set_bit(_DOMF_constructed, &d->domain_flags); + + printk("calling new_thread, entry=%p\n",pkern_entry); +#ifdef DOMU_AUTO_RESTART + v->domain->arch.image_start = image_start; + v->domain->arch.image_len = image_len; + v->domain->arch.entry = pkern_entry; +#endif + new_thread(v, pkern_entry, 0, 0); + printk("new_thread returns\n"); + __set_bit(0x30, VCPU(v, delivery_mask)); + + return 0; +} + +#ifdef DOMU_AUTO_RESTART +void reconstruct_domU(struct vcpu *v) +{ + /* re-copy the OS image to reset data values to original */ + printk("reconstruct_domU: restarting domain %d...\n", + v->domain->domain_id); + loaddomainelfimage(v->domain,v->domain->arch.image_start); + new_thread(v, v->domain->arch.entry, 0, 0); +} +#endif + +// FIXME: When dom0 can construct domains, this goes away (or is rewritten) +int launch_domainU(unsigned long size) +{ +#ifdef CLONE_DOMAIN0 + static int next = CLONE_DOMAIN0+1; +#else + static int next = 1; +#endif + + struct domain *d = do_createdomain(next,0); + if (!d) { + printf("launch_domainU: couldn't create\n"); + return 1; + } + else next++; + if (construct_domU(d, (unsigned long)domU_staging_area, size,0,0,0)) { + printf("launch_domainU: couldn't construct(id=%d,%lx,%lx)\n", + d->domain_id,domU_staging_area,size); + return 2; + } + domain_unpause_by_systemcontroller(d); +} + +void machine_restart(char * __unused) +{ + if (platform_is_hp_ski()) dummy(); + printf("machine_restart called: spinning....\n"); + while(1); +} + +void machine_halt(void) +{ + if (platform_is_hp_ski()) dummy(); + printf("machine_halt called: spinning....\n"); + while(1); +} + +void dummy_called(char *function) +{ + if (platform_is_hp_ski()) asm("break 0;;"); + printf("dummy called in %s: spinning....\n", function); + while(1); +} + + +#if 0 +void switch_to(struct vcpu *prev, struct vcpu *next) +{ + struct vcpu *last; + + __switch_to(prev,next,last); + //set_current(next); +} +#endif + +void domain_pend_keyboard_interrupt(int irq) +{ + vcpu_pend_interrupt(dom0->vcpu[0],irq); +} + +void vcpu_migrate_cpu(struct vcpu *v, int newcpu) +{ + if ( v->processor == newcpu ) + return; + + set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags); + v->processor = newcpu; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/grant_table.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/grant_table.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1288 @@ +#ifndef CONFIG_VTI +// temporarily in arch/ia64 until can merge into common/grant_table.c +/****************************************************************************** + * common/grant_table.c + * + * Mechanism for granting foreign access to page frames, and receiving + * page-ownership transfers. + * + * Copyright (c) 2005 Christopher Clark + * Copyright (c) 2004 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define GRANT_DEBUG 0 +#define GRANT_DEBUG_VERBOSE 0 + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/sched.h> +#include <xen/shadow.h> +#include <xen/mm.h> +#ifdef __ia64__ +#define __addr_ok(a) 1 // FIXME-ia64: a variant of access_ok?? +// FIXME-ia64: need to implement real cmpxchg_user on ia64 +//#define cmpxchg_user(_p,_o,_n) ((*_p == _o) ? ((*_p = _n), 0) : ((_o = *_p), 0)) +// FIXME-ia64: these belong in an asm/grant_table.h... PAGE_SIZE different +#undef ORDER_GRANT_FRAMES +//#undef NUM_GRANT_FRAMES +#define ORDER_GRANT_FRAMES 0 +//#define NUM_GRANT_FRAMES (1U << ORDER_GRANT_FRAMES) +#endif + +#define PIN_FAIL(_lbl, _rc, _f, _a...) \ + do { \ + DPRINTK( _f, ## _a ); \ + rc = (_rc); \ + goto _lbl; \ + } while ( 0 ) + +static inline int +get_maptrack_handle( + grant_table_t *t) +{ + unsigned int h; + if ( unlikely((h = t->maptrack_head) == t->maptrack_limit) ) + return -1; + t->maptrack_head = t->maptrack[h].ref_and_flags >> MAPTRACK_REF_SHIFT; + t->map_count++; + return h; +} + +static inline void +put_maptrack_handle( + grant_table_t *t, int handle) +{ + t->maptrack[handle].ref_and_flags = t->maptrack_head << MAPTRACK_REF_SHIFT; + t->maptrack_head = handle; + t->map_count--; +} + +static int +__gnttab_activate_grant_ref( + struct domain *mapping_d, /* IN */ + struct vcpu *mapping_ed, + struct domain *granting_d, + grant_ref_t ref, + u16 dev_hst_ro_flags, + unsigned long host_virt_addr, + unsigned long *pframe ) /* OUT */ +{ + domid_t sdom; + u16 sflags; + active_grant_entry_t *act; + grant_entry_t *sha; + s16 rc = 1; + unsigned long frame = 0; + int retries = 0; + + /* + * Objectives of this function: + * . Make the record ( granting_d, ref ) active, if not already. + * . Update shared grant entry of owner, indicating frame is mapped. + * . Increment the owner act->pin reference counts. + * . get_page on shared frame if new mapping. + * . get_page_type if this is first RW mapping of frame. + * . Add PTE to virtual address space of mapping_d, if necessary. + * Returns: + * . -ve: error + * . 1: ok + * . 0: ok and TLB invalidate of host_virt_addr needed. + * + * On success, *pframe contains mfn. + */ + + /* + * We bound the number of times we retry CMPXCHG on memory locations that + * we share with a guest OS. The reason is that the guest can modify that + * location at a higher rate than we can read-modify-CMPXCHG, so the guest + * could cause us to livelock. There are a few cases where it is valid for + * the guest to race our updates (e.g., to change the GTF_readonly flag), + * so we allow a few retries before failing. + */ + + act = &granting_d->grant_table->active[ref]; + sha = &granting_d->grant_table->shared[ref]; + + spin_lock(&granting_d->grant_table->lock); + + if ( act->pin == 0 ) + { + /* CASE 1: Activating a previously inactive entry. */ + + sflags = sha->flags; + sdom = sha->domid; + + for ( ; ; ) + { + u32 scombo, prev_scombo, new_scombo; + + if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) || + unlikely(sdom != mapping_d->domain_id) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", + sflags, sdom, mapping_d->domain_id); + + /* Merge two 16-bit values into a 32-bit combined update. */ + /* NB. Endianness! */ + prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; + + new_scombo = scombo | GTF_reading; + if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) + { + new_scombo |= GTF_writing; + if ( unlikely(sflags & GTF_readonly) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Attempt to write-pin a r/o grant entry.\n"); + } + + /* NB. prev_scombo is updated in place to seen value. */ + if ( unlikely(cmpxchg_user((u32 *)&sha->flags, + prev_scombo, + new_scombo)) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Fault while modifying shared flags and domid.\n"); + + /* Did the combined update work (did we see what we expected?). */ + if ( likely(prev_scombo == scombo) ) + break; + + if ( retries++ == 4 ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Shared grant entry is unstable.\n"); + + /* Didn't see what we expected. Split out the seen flags & dom. */ + /* NB. Endianness! */ + sflags = (u16)prev_scombo; + sdom = (u16)(prev_scombo >> 16); + } + + /* rmb(); */ /* not on x86 */ + + frame = __gpfn_to_mfn_foreign(granting_d, sha->frame); + +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? +#else + if ( unlikely(!pfn_valid(frame)) || + unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ? + get_page(&frame_table[frame], granting_d) : + get_page_and_type(&frame_table[frame], granting_d, + PGT_writable_page))) ) + { + clear_bit(_GTF_writing, &sha->flags); + clear_bit(_GTF_reading, &sha->flags); + PIN_FAIL(unlock_out, GNTST_general_error, + "Could not pin the granted frame (%lx)!\n", frame); + } +#endif + + if ( dev_hst_ro_flags & GNTMAP_device_map ) + act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? + GNTPIN_devr_inc : GNTPIN_devw_inc; + if ( dev_hst_ro_flags & GNTMAP_host_map ) + act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? + GNTPIN_hstr_inc : GNTPIN_hstw_inc; + act->domid = sdom; + act->frame = frame; + } + else + { + /* CASE 2: Active modications to an already active entry. */ + + /* + * A cheesy check for possible pin-count overflow. + * A more accurate check cannot be done with a single comparison. + */ + if ( (act->pin & 0x80808080U) != 0 ) + PIN_FAIL(unlock_out, ENOSPC, + "Risk of counter overflow %08x\n", act->pin); + + frame = act->frame; + + if ( !(dev_hst_ro_flags & GNTMAP_readonly) && + !((sflags = sha->flags) & GTF_writing) ) + { + for ( ; ; ) + { + u16 prev_sflags; + + if ( unlikely(sflags & GTF_readonly) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Attempt to write-pin a r/o grant entry.\n"); + + prev_sflags = sflags; + + /* NB. prev_sflags is updated in place to seen value. */ + if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags, + prev_sflags | GTF_writing)) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Fault while modifying shared flags.\n"); + + if ( likely(prev_sflags == sflags) ) + break; + + if ( retries++ == 4 ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Shared grant entry is unstable.\n"); + + sflags = prev_sflags; + } + +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? +#else + if ( unlikely(!get_page_type(&frame_table[frame], + PGT_writable_page)) ) + { + clear_bit(_GTF_writing, &sha->flags); + PIN_FAIL(unlock_out, GNTST_general_error, + "Attempt to write-pin a unwritable page.\n"); + } +#endif + } + + if ( dev_hst_ro_flags & GNTMAP_device_map ) + act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? + GNTPIN_devr_inc : GNTPIN_devw_inc; + + if ( dev_hst_ro_flags & GNTMAP_host_map ) + act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? + GNTPIN_hstr_inc : GNTPIN_hstw_inc; + } + + /* + * At this point: + * act->pin updated to reflect mapping. + * sha->flags updated to indicate to granting domain mapping done. + * frame contains the mfn. + */ + + spin_unlock(&granting_d->grant_table->lock); + +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? +#else + if ( (host_virt_addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) ) + { + /* Write update into the pagetable. */ + l1_pgentry_t pte; + pte = l1e_from_pfn(frame, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); + if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) + l1e_add_flags(pte,_PAGE_RW); + rc = update_grant_va_mapping( host_virt_addr, pte, + mapping_d, mapping_ed ); + + /* + * IMPORTANT: (rc == 0) => must flush / invalidate entry in TLB. + * This is done in the outer gnttab_map_grant_ref. + */ + + if ( rc < 0 ) + { + /* Failure: undo and abort. */ + + spin_lock(&granting_d->grant_table->lock); + + if ( dev_hst_ro_flags & GNTMAP_readonly ) + { + act->pin -= GNTPIN_hstr_inc; + } + else + { + act->pin -= GNTPIN_hstw_inc; + if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) + { + clear_bit(_GTF_writing, &sha->flags); + put_page_type(&frame_table[frame]); + } + } + + if ( act->pin == 0 ) + { + clear_bit(_GTF_reading, &sha->flags); + put_page(&frame_table[frame]); + } + + spin_unlock(&granting_d->grant_table->lock); + } + + } +#endif + + *pframe = frame; + return rc; + + unlock_out: + spin_unlock(&granting_d->grant_table->lock); + return rc; +} + +/* + * Returns 0 if TLB flush / invalidate required by caller. + * va will indicate the address to be invalidated. + */ +static int +__gnttab_map_grant_ref( + gnttab_map_grant_ref_t *uop, + unsigned long *va) +{ + domid_t dom; + grant_ref_t ref; + struct domain *ld, *rd; + struct vcpu *led; + u16 dev_hst_ro_flags; + int handle; + unsigned long frame = 0, host_virt_addr; + int rc; + + led = current; + ld = led->domain; + + /* Bitwise-OR avoids short-circuiting which screws control flow. */ + if ( unlikely(__get_user(dom, &uop->dom) | + __get_user(ref, &uop->ref) | + __get_user(host_virt_addr, &uop->host_addr) | + __get_user(dev_hst_ro_flags, &uop->flags)) ) + { + DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n"); + return -EFAULT; /* don't set status */ + } + + + if ( ((host_virt_addr != 0) || (dev_hst_ro_flags & GNTMAP_host_map)) && + unlikely(!__addr_ok(host_virt_addr))) + { + DPRINTK("Bad virtual address (%lx) or flags (%x).\n", + host_virt_addr, dev_hst_ro_flags); + (void)__put_user(GNTST_bad_virt_addr, &uop->handle); + return GNTST_bad_gntref; + } + + if ( unlikely(ref >= NR_GRANT_ENTRIES) || + unlikely((dev_hst_ro_flags & + (GNTMAP_device_map|GNTMAP_host_map)) == 0) ) + { + DPRINTK("Bad ref (%d) or flags (%x).\n", ref, dev_hst_ro_flags); + (void)__put_user(GNTST_bad_gntref, &uop->handle); + return GNTST_bad_gntref; + } + + if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || + unlikely(ld == rd) ) + { + if ( rd != NULL ) + put_domain(rd); + DPRINTK("Could not find domain %d\n", dom); + (void)__put_user(GNTST_bad_domain, &uop->handle); + return GNTST_bad_domain; + } + + /* Get a maptrack handle. */ + if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) ) + { + int i; + grant_mapping_t *new_mt; + grant_table_t *lgt = ld->grant_table; + + /* Grow the maptrack table. */ + new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1); + if ( new_mt == NULL ) + { + put_domain(rd); + DPRINTK("No more map handles available\n"); + (void)__put_user(GNTST_no_device_space, &uop->handle); + return GNTST_no_device_space; + } + + memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order); + for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ ) + new_mt[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; + + free_xenheap_pages(lgt->maptrack, lgt->maptrack_order); + lgt->maptrack = new_mt; + lgt->maptrack_order += 1; + lgt->maptrack_limit <<= 1; + + printk("Doubled maptrack size\n"); + handle = get_maptrack_handle(ld->grant_table); + } + +#if GRANT_DEBUG_VERBOSE + DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n", + ref, dom, dev_hst_ro_flags); +#endif + + if ( 0 <= ( rc = __gnttab_activate_grant_ref( ld, led, rd, ref, + dev_hst_ro_flags, + host_virt_addr, &frame))) + { + /* + * Only make the maptrack live _after_ writing the pte, in case we + * overwrite the same frame number, causing a maptrack walk to find it + */ + ld->grant_table->maptrack[handle].domid = dom; + + ld->grant_table->maptrack[handle].ref_and_flags + = (ref << MAPTRACK_REF_SHIFT) | + (dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK); + + (void)__put_user(frame, &uop->dev_bus_addr); + + if ( dev_hst_ro_flags & GNTMAP_host_map ) + *va = host_virt_addr; + + (void)__put_user(handle, &uop->handle); + } + else + { + (void)__put_user(rc, &uop->handle); + put_maptrack_handle(ld->grant_table, handle); + } + + put_domain(rd); + return rc; +} + +static long +gnttab_map_grant_ref( + gnttab_map_grant_ref_t *uop, unsigned int count) +{ + int i, flush = 0; + unsigned long va = 0; + + for ( i = 0; i < count; i++ ) + if ( __gnttab_map_grant_ref(&uop[i], &va) == 0 ) + flush++; + +#ifdef __ia64__ +// FIXME-ia64: probably need to do something here to avoid stale mappings? +#else + if ( flush == 1 ) + flush_tlb_one_mask(current->domain->cpumask, va); + else if ( flush != 0 ) + flush_tlb_mask(current->domain->cpumask); +#endif + + return 0; +} + +static int +__gnttab_unmap_grant_ref( + gnttab_unmap_grant_ref_t *uop, + unsigned long *va) +{ + domid_t dom; + grant_ref_t ref; + u16 handle; + struct domain *ld, *rd; + + active_grant_entry_t *act; + grant_entry_t *sha; + grant_mapping_t *map; + u16 flags; + s16 rc = 1; + unsigned long frame, virt; + + ld = current->domain; + + /* Bitwise-OR avoids short-circuiting which screws control flow. */ + if ( unlikely(__get_user(virt, &uop->host_addr) | + __get_user(frame, &uop->dev_bus_addr) | + __get_user(handle, &uop->handle)) ) + { + DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n"); + return -EFAULT; /* don't set status */ + } + + map = &ld->grant_table->maptrack[handle]; + + if ( unlikely(handle >= ld->grant_table->maptrack_limit) || + unlikely(!(map->ref_and_flags & MAPTRACK_GNTMAP_MASK)) ) + { + DPRINTK("Bad handle (%d).\n", handle); + (void)__put_user(GNTST_bad_handle, &uop->status); + return GNTST_bad_handle; + } + + dom = map->domid; + ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; + flags = map->ref_and_flags & MAPTRACK_GNTMAP_MASK; + + if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || + unlikely(ld == rd) ) + { + if ( rd != NULL ) + put_domain(rd); + DPRINTK("Could not find domain %d\n", dom); + (void)__put_user(GNTST_bad_domain, &uop->status); + return GNTST_bad_domain; + } + +#if GRANT_DEBUG_VERBOSE + DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n", + ref, dom, handle); +#endif + + act = &rd->grant_table->active[ref]; + sha = &rd->grant_table->shared[ref]; + + spin_lock(&rd->grant_table->lock); + + if ( frame == 0 ) + { + frame = act->frame; + } + else + { + if ( unlikely(frame != act->frame) ) + PIN_FAIL(unmap_out, GNTST_general_error, + "Bad frame number doesn't match gntref.\n"); + if ( flags & GNTMAP_device_map ) + act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc + : GNTPIN_devw_inc; + + map->ref_and_flags &= ~GNTMAP_device_map; + (void)__put_user(0, &uop->dev_bus_addr); + + /* Frame is now unmapped for device access. */ + } + + if ( (virt != 0) && + (flags & GNTMAP_host_map) && + ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0)) + { +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? +#else + l1_pgentry_t *pl1e; + unsigned long _ol1e; + + pl1e = &linear_pg_table[l1_linear_offset(virt)]; + + if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) ) + { + DPRINTK("Could not find PTE entry for address %lx\n", virt); + rc = -EINVAL; + goto unmap_out; + } + + /* + * Check that the virtual address supplied is actually mapped to + * act->frame. + */ + if ( unlikely((_ol1e >> PAGE_SHIFT) != frame )) + { + DPRINTK("PTE entry %lx for address %lx doesn't match frame %lx\n", + _ol1e, virt, frame); + rc = -EINVAL; + goto unmap_out; + } + + /* Delete pagetable entry. */ + if ( unlikely(__put_user(0, (unsigned long *)pl1e))) + { + DPRINTK("Cannot delete PTE entry at %p for virtual address %lx\n", + pl1e, virt); + rc = -EINVAL; + goto unmap_out; + } +#endif + + map->ref_and_flags &= ~GNTMAP_host_map; + + act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc + : GNTPIN_hstw_inc; + + rc = 0; + *va = virt; + } + + if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) + { + map->ref_and_flags = 0; + put_maptrack_handle(ld->grant_table, handle); + } + +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? I think not and then +// this can probably be macro-ized into nothingness +#else + /* If just unmapped a writable mapping, mark as dirtied */ + if ( unlikely(shadow_mode_log_dirty(rd)) && + !( flags & GNTMAP_readonly ) ) + mark_dirty(rd, frame); +#endif + + /* If the last writable mapping has been removed, put_page_type */ + if ( ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask) ) == 0) && + ( !( flags & GNTMAP_readonly ) ) ) + { + clear_bit(_GTF_writing, &sha->flags); + put_page_type(&frame_table[frame]); + } + + if ( act->pin == 0 ) + { + clear_bit(_GTF_reading, &sha->flags); + put_page(&frame_table[frame]); + } + + unmap_out: + (void)__put_user(rc, &uop->status); + spin_unlock(&rd->grant_table->lock); + put_domain(rd); + return rc; +} + +static long +gnttab_unmap_grant_ref( + gnttab_unmap_grant_ref_t *uop, unsigned int count) +{ + int i, flush = 0; + unsigned long va = 0; + + for ( i = 0; i < count; i++ ) + if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 ) + flush++; + +#ifdef __ia64__ +// FIXME-ia64: probably need to do something here to avoid stale mappings? +#else + if ( flush == 1 ) + flush_tlb_one_mask(current->domain->cpumask, va); + else if ( flush != 0 ) + flush_tlb_mask(current->domain->cpumask); +#endif + + return 0; +} + +static long +gnttab_setup_table( + gnttab_setup_table_t *uop, unsigned int count) +{ + gnttab_setup_table_t op; + struct domain *d; + int i; + unsigned long addr; + + if ( count != 1 ) + return -EINVAL; + + if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) + { + DPRINTK("Fault while reading gnttab_setup_table_t.\n"); + return -EFAULT; + } + + if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) ) + { + DPRINTK("Xen only supports up to %d grant-table frames per domain.\n", + NR_GRANT_FRAMES); + (void)put_user(GNTST_general_error, &uop->status); + return 0; + } + + if ( op.dom == DOMID_SELF ) + { + op.dom = current->domain->domain_id; + } + else if ( unlikely(!IS_PRIV(current->domain)) ) + { + (void)put_user(GNTST_permission_denied, &uop->status); + return 0; + } + + if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) + { + DPRINTK("Bad domid %d.\n", op.dom); + (void)put_user(GNTST_bad_domain, &uop->status); + return 0; + } + + if ( op.nr_frames <= NR_GRANT_FRAMES ) + { + ASSERT(d->grant_table != NULL); + (void)put_user(GNTST_okay, &uop->status); +#ifdef __ia64__ + if (d == dom0) { + for ( i = 0; i < op.nr_frames; i++ ) + (void)put_user( + (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, + &uop->frame_list[i]); + } else { + /* IA64 hack - need to map it somewhere */ + addr = (1UL << 40); + map_domain_page(d, addr, virt_to_phys(d->grant_table->shared)); + (void)put_user(addr >> PAGE_SHIFT, &uop->frame_list[0]); + } +#else + for ( i = 0; i < op.nr_frames; i++ ) + (void)put_user( + (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, + &uop->frame_list[i]); +#endif + } + + put_domain(d); + return 0; +} + +#if GRANT_DEBUG +static int +gnttab_dump_table(gnttab_dump_table_t *uop) +{ + grant_table_t *gt; + gnttab_dump_table_t op; + struct domain *d; + u32 shared_mfn; + active_grant_entry_t *act; + grant_entry_t sha_copy; + grant_mapping_t *maptrack; + int i; + + + if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) + { + DPRINTK("Fault while reading gnttab_dump_table_t.\n"); + return -EFAULT; + } + + if ( op.dom == DOMID_SELF ) + { + op.dom = current->domain->domain_id; + } + + if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) + { + DPRINTK("Bad domid %d.\n", op.dom); + (void)put_user(GNTST_bad_domain, &uop->status); + return 0; + } + + ASSERT(d->grant_table != NULL); + gt = d->grant_table; + (void)put_user(GNTST_okay, &uop->status); + + shared_mfn = virt_to_phys(d->grant_table->shared); + + DPRINTK("Grant table for dom (%hu) MFN (%x)\n", + op.dom, shared_mfn); + + ASSERT(d->grant_table->active != NULL); + ASSERT(d->grant_table->shared != NULL); + ASSERT(d->grant_table->maptrack != NULL); + + for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) + { + sha_copy = gt->shared[i]; + + if ( sha_copy.flags ) + { + DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) " + "dom:(%hu) frame:(%lx)\n", + op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame); + } + } + + spin_lock(>->lock); + + for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) + { + act = >->active[i]; + + if ( act->pin ) + { + DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) " + "dom:(%hu) frame:(%lx)\n", + op.dom, i, act->pin, act->domid, act->frame); + } + } + + for ( i = 0; i < gt->maptrack_limit; i++ ) + { + maptrack = >->maptrack[i]; + + if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK ) + { + DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) " + "dom:(%hu)\n", + op.dom, i, + maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT, + maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK, + maptrack->domid); + } + } + + spin_unlock(>->lock); + + put_domain(d); + return 0; +} +#endif + +long +do_grant_table_op( + unsigned int cmd, void *uop, unsigned int count) +{ + long rc; + + if ( count > 512 ) + return -EINVAL; + + LOCK_BIGLOCK(current->domain); + + rc = -EFAULT; + switch ( cmd ) + { + case GNTTABOP_map_grant_ref: + if ( unlikely(!array_access_ok( + uop, count, sizeof(gnttab_map_grant_ref_t))) ) + goto out; + rc = gnttab_map_grant_ref((gnttab_map_grant_ref_t *)uop, count); + break; + case GNTTABOP_unmap_grant_ref: + if ( unlikely(!array_access_ok( + uop, count, sizeof(gnttab_unmap_grant_ref_t))) ) + goto out; + rc = gnttab_unmap_grant_ref((gnttab_unmap_grant_ref_t *)uop, count); + break; + case GNTTABOP_setup_table: + rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count); + break; +#if GRANT_DEBUG + case GNTTABOP_dump_table: + rc = gnttab_dump_table((gnttab_dump_table_t *)uop); + break; +#endif + default: + rc = -ENOSYS; + break; + } + +out: + UNLOCK_BIGLOCK(current->domain); + + return rc; +} + +int +gnttab_check_unmap( + struct domain *rd, struct domain *ld, unsigned long frame, int readonly) +{ + /* Called when put_page is invoked on a page belonging to a foreign domain. + * Instead of decrementing the frame table ref count, locate the grant + * table entry, if any, and if found, decrement that count. + * Called a _lot_ at domain creation because pages mapped by priv domains + * also traverse this. + */ + + /* Note: If the same frame is mapped multiple times, and then one of + * the ptes is overwritten, which maptrack handle gets invalidated? + * Advice: Don't do it. Explicitly unmap. + */ + + unsigned int handle, ref, refcount; + grant_table_t *lgt, *rgt; + active_grant_entry_t *act; + grant_mapping_t *map; + int found = 0; + + lgt = ld->grant_table; + +#if GRANT_DEBUG_VERBOSE + if ( ld->domain_id != 0 ) + { + DPRINTK("Foreign unref rd(%d) ld(%d) frm(%x) flgs(%x).\n", + rd->domain_id, ld->domain_id, frame, readonly); + } +#endif + + /* Fast exit if we're not mapping anything using grant tables */ + if ( lgt->map_count == 0 ) + return 0; + + if ( get_domain(rd) == 0 ) + { + DPRINTK("gnttab_check_unmap: couldn't get_domain rd(%d)\n", + rd->domain_id); + return 0; + } + + rgt = rd->grant_table; + + for ( handle = 0; handle < lgt->maptrack_limit; handle++ ) + { + map = &lgt->maptrack[handle]; + + if ( ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK ) && + ( readonly ? 1 : (!(map->ref_and_flags & GNTMAP_readonly)))) + { + ref = (map->ref_and_flags >> MAPTRACK_REF_SHIFT); + act = &rgt->active[ref]; + + spin_lock(&rgt->lock); + + if ( act->frame != frame ) + { + spin_unlock(&rgt->lock); + continue; + } + + refcount = act->pin & ( readonly ? GNTPIN_hstr_mask + : GNTPIN_hstw_mask ); + if ( refcount == 0 ) + { + spin_unlock(&rgt->lock); + continue; + } + + /* gotcha */ + DPRINTK("Grant unref rd(%d) ld(%d) frm(%lx) flgs(%x).\n", + rd->domain_id, ld->domain_id, frame, readonly); + + if ( readonly ) + act->pin -= GNTPIN_hstr_inc; + else + { + act->pin -= GNTPIN_hstw_inc; + + /* any more granted writable mappings? */ + if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) + { + clear_bit(_GTF_writing, &rgt->shared[ref].flags); + put_page_type(&frame_table[frame]); + } + } + + if ( act->pin == 0 ) + { + clear_bit(_GTF_reading, &rgt->shared[ref].flags); + put_page(&frame_table[frame]); + } + spin_unlock(&rgt->lock); + + clear_bit(GNTMAP_host_map, &map->ref_and_flags); + + if ( !(map->ref_and_flags & GNTMAP_device_map) ) + put_maptrack_handle(lgt, handle); + + found = 1; + break; + } + } + put_domain(rd); + + return found; +} + +int +gnttab_prepare_for_transfer( + struct domain *rd, struct domain *ld, grant_ref_t ref) +{ + grant_table_t *rgt; + grant_entry_t *sha; + domid_t sdom; + u16 sflags; + u32 scombo, prev_scombo; + int retries = 0; + unsigned long target_pfn; + + DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n", + rd->domain_id, ld->domain_id, ref); + + if ( unlikely((rgt = rd->grant_table) == NULL) || + unlikely(ref >= NR_GRANT_ENTRIES) ) + { + DPRINTK("Dom %d has no g.t., or ref is bad (%d).\n", + rd->domain_id, ref); + return 0; + } + + spin_lock(&rgt->lock); + + sha = &rgt->shared[ref]; + + sflags = sha->flags; + sdom = sha->domid; + + for ( ; ; ) + { + target_pfn = sha->frame; + + if ( unlikely(target_pfn >= max_page ) ) + { + DPRINTK("Bad pfn (%lx)\n", target_pfn); + goto fail; + } + + if ( unlikely(sflags != GTF_accept_transfer) || + unlikely(sdom != ld->domain_id) ) + { + DPRINTK("Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", + sflags, sdom, ld->domain_id); + goto fail; + } + + /* Merge two 16-bit values into a 32-bit combined update. */ + /* NB. Endianness! */ + prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; + + /* NB. prev_scombo is updated in place to seen value. */ + if ( unlikely(cmpxchg_user((u32 *)&sha->flags, prev_scombo, + prev_scombo | GTF_transfer_committed)) ) + { + DPRINTK("Fault while modifying shared flags and domid.\n"); + goto fail; + } + + /* Did the combined update work (did we see what we expected?). */ + if ( likely(prev_scombo == scombo) ) + break; + + if ( retries++ == 4 ) + { + DPRINTK("Shared grant entry is unstable.\n"); + goto fail; + } + + /* Didn't see what we expected. Split out the seen flags & dom. */ + /* NB. Endianness! */ + sflags = (u16)prev_scombo; + sdom = (u16)(prev_scombo >> 16); + } + + spin_unlock(&rgt->lock); + return 1; + + fail: + spin_unlock(&rgt->lock); + return 0; +} + +void +gnttab_notify_transfer( + struct domain *rd, struct domain *ld, grant_ref_t ref, unsigned long frame) +{ + grant_entry_t *sha; + unsigned long pfn; + + DPRINTK("gnttab_notify_transfer rd(%hu) ld(%hu) ref(%hu).\n", + rd->domain_id, ld->domain_id, ref); + + sha = &rd->grant_table->shared[ref]; + + spin_lock(&rd->grant_table->lock); + +#ifdef __ia64__ +// FIXME-ia64: any error checking need to be done here? +#else + pfn = sha->frame; + + if ( unlikely(pfn >= max_page ) ) + DPRINTK("Bad pfn (%lx)\n", pfn); + else + { + machine_to_phys_mapping[frame] = pfn; + + if ( unlikely(shadow_mode_log_dirty(ld))) + mark_dirty(ld, frame); + + if (shadow_mode_translate(ld)) + __phys_to_machine_mapping[pfn] = frame; + } +#endif + sha->frame = __mfn_to_gpfn(rd, frame); + sha->domid = rd->domain_id; + wmb(); + sha->flags = ( GTF_accept_transfer | GTF_transfer_completed ); + + spin_unlock(&rd->grant_table->lock); + + return; +} + +int +grant_table_create( + struct domain *d) +{ + grant_table_t *t; + int i; + + if ( (t = xmalloc(grant_table_t)) == NULL ) + goto no_mem; + + /* Simple stuff. */ + memset(t, 0, sizeof(*t)); + spin_lock_init(&t->lock); + + /* Active grant table. */ + if ( (t->active = xmalloc_array(active_grant_entry_t, NR_GRANT_ENTRIES)) + == NULL ) + goto no_mem; + memset(t->active, 0, sizeof(active_grant_entry_t) * NR_GRANT_ENTRIES); + + /* Tracking of mapped foreign frames table */ + if ( (t->maptrack = alloc_xenheap_page()) == NULL ) + goto no_mem; + t->maptrack_order = 0; + t->maptrack_limit = PAGE_SIZE / sizeof(grant_mapping_t); + memset(t->maptrack, 0, PAGE_SIZE); + for ( i = 0; i < t->maptrack_limit; i++ ) + t->maptrack[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; + + /* Shared grant table. */ + t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES); + if ( t->shared == NULL ) + goto no_mem; + memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE); + +#ifdef __ia64__ +// I don't think there's anything to do here on ia64?... +#else + for ( i = 0; i < NR_GRANT_FRAMES; i++ ) + { + SHARE_PFN_WITH_DOMAIN( + virt_to_page((char *)(t->shared)+(i*PAGE_SIZE)), d); + machine_to_phys_mapping[(virt_to_phys(t->shared) >> PAGE_SHIFT) + i] = + INVALID_M2P_ENTRY; + } +#endif + + /* Okay, install the structure. */ + wmb(); /* avoid races with lock-free access to d->grant_table */ + d->grant_table = t; + return 0; + + no_mem: + if ( t != NULL ) + { + xfree(t->active); + if ( t->maptrack != NULL ) + free_xenheap_page(t->maptrack); + xfree(t); + } + return -ENOMEM; +} + +void +gnttab_release_dev_mappings(grant_table_t *gt) +{ + grant_mapping_t *map; + domid_t dom; + grant_ref_t ref; + u16 handle; + struct domain *ld, *rd; + unsigned long frame; + active_grant_entry_t *act; + grant_entry_t *sha; + + ld = current->domain; + + for ( handle = 0; handle < gt->maptrack_limit; handle++ ) + { + map = >->maptrack[handle]; + + if ( map->ref_and_flags & GNTMAP_device_map ) + { + dom = map->domid; + ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; + + DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n", + handle, ref, + map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom); + + if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || + unlikely(ld == rd) ) + { + if ( rd != NULL ) + put_domain(rd); + + printk(KERN_WARNING "Grant release: No dom%d\n", dom); + continue; + } + + act = &rd->grant_table->active[ref]; + sha = &rd->grant_table->shared[ref]; + + spin_lock(&rd->grant_table->lock); + + if ( act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask) ) + { + frame = act->frame; + + if ( ( (act->pin & GNTPIN_hstw_mask) == 0 ) && + ( (act->pin & GNTPIN_devw_mask) > 0 ) ) + { + clear_bit(_GTF_writing, &sha->flags); + put_page_type(&frame_table[frame]); + } + + act->pin &= ~(GNTPIN_devw_mask | GNTPIN_devr_mask); + + if ( act->pin == 0 ) + { + clear_bit(_GTF_reading, &sha->flags); + map->ref_and_flags = 0; + put_page(&frame_table[frame]); + } + else + map->ref_and_flags &= ~GNTMAP_device_map; + } + + spin_unlock(&rd->grant_table->lock); + + put_domain(rd); + } + } +} + + +void +grant_table_destroy( + struct domain *d) +{ + grant_table_t *t; + + if ( (t = d->grant_table) != NULL ) + { + /* Free memory relating to this grant table. */ + d->grant_table = NULL; + free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES); + free_xenheap_page(t->maptrack); + xfree(t->active); + xfree(t); + } +} + +void +grant_table_init( + void) +{ + /* Nothing. */ +} +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/hpsimserial.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/hpsimserial.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,23 @@ +/* + * HP Ski simulator serial I/O + * + * Copyright (C) 2004 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ + +#include <linux/config.h> +#include <xen/sched.h> +#include <xen/serial.h> +#include "hpsim_ssc.h" + +static void hp_ski_putc(struct serial_port *port, char c) +{ + ia64_ssc(c,0,0,0,SSC_PUTCHAR); +} + +static struct uart_driver hp_ski = { .putc = hp_ski_putc }; + +void hpsim_serial_init(void) +{ + serial_register_uart(0, &hp_ski, 0); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/hypercall.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/hypercall.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,182 @@ +/* + * Hypercall implementations + * + * Copyright (C) 2005 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <xen/config.h> +#include <xen/sched.h> + +#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ +#include <asm/sal.h> /* FOR struct ia64_sal_retval */ + +#include <asm/vcpu.h> +#include <asm/dom_fw.h> + +extern unsigned long translate_domain_mpaddr(unsigned long); +extern struct ia64_pal_retval xen_pal_emulator(UINT64,UINT64,UINT64,UINT64); +extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); + +unsigned long idle_when_pending = 0; +unsigned long pal_halt_light_count = 0; + +int +ia64_hypercall (struct pt_regs *regs) +{ + struct vcpu *v = (struct domain *) current; + struct ia64_sal_retval x; + struct ia64_pal_retval y; + unsigned long *tv, *tc; + int pi; + + switch (regs->r2) { + case FW_HYPERCALL_PAL_CALL: + //printf("*** PAL hypercall: index=%d\n",regs->r28); + //FIXME: This should call a C routine +#if 0 + // This is very conservative, but avoids a possible + // (and deadly) freeze in paravirtualized domains due + // to a yet-to-be-found bug where pending_interruption + // is zero when it shouldn't be. Since PAL is called + // in the idle loop, this should resolve it + VCPU(v,pending_interruption) = 1; +#endif + if (regs->r28 == PAL_HALT_LIGHT) { +#define SPURIOUS_VECTOR 15 + pi = vcpu_check_pending_interrupts(v); + if (pi != SPURIOUS_VECTOR) { + if (!VCPU(v,pending_interruption)) + idle_when_pending++; + vcpu_pend_unspecified_interrupt(v); +//printf("idle w/int#%d pending!\n",pi); +//this shouldn't happen, but it apparently does quite a bit! so don't +//allow it to happen... i.e. if a domain has an interrupt pending and +//it tries to halt itself because it thinks it is idle, just return here +//as deliver_pending_interrupt is called on the way out and will deliver it + } + else { + pal_halt_light_count++; + do_sched_op(SCHEDOP_yield); + } + //break; + } + else if (regs->r28 >= PAL_COPY_PAL) { /* FIXME */ + printf("stacked PAL hypercalls not supported\n"); + regs->r8 = -1; + break; + } + else y = xen_pal_emulator(regs->r28,regs->r29, + regs->r30,regs->r31); + regs->r8 = y.status; regs->r9 = y.v0; + regs->r10 = y.v1; regs->r11 = y.v2; + break; + 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), + vcpu_get_gr(v,38),vcpu_get_gr(v,39)); + regs->r8 = x.status; regs->r9 = x.v0; + regs->r10 = x.v1; regs->r11 = x.v2; + break; + case FW_HYPERCALL_EFI_RESET_SYSTEM: + printf("efi.reset_system called "); + if (current->domain == dom0) { + printf("(by dom0)\n "); + (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL); + } +#ifdef DOMU_AUTO_RESTART + else { + reconstruct_domU(current); + return 0; // don't increment ip! + } +#else + printf("(not supported for non-0 domain)\n"); + regs->r8 = EFI_UNSUPPORTED; +#endif + break; + case FW_HYPERCALL_EFI_GET_TIME: + tv = vcpu_get_gr(v,32); + tc = vcpu_get_gr(v,33); + //printf("efi_get_time(%p,%p) called...",tv,tc); + tv = __va(translate_domain_mpaddr(tv)); + if (tc) tc = __va(translate_domain_mpaddr(tc)); + regs->r8 = (*efi.get_time)(tv,tc); + //printf("and returns %lx\n",regs->r8); + break; + case FW_HYPERCALL_EFI_SET_TIME: + case FW_HYPERCALL_EFI_GET_WAKEUP_TIME: + case FW_HYPERCALL_EFI_SET_WAKEUP_TIME: + // FIXME: need fixes in efi.h from 2.6.9 + case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP: + // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED + // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS + // POINTER ARGUMENTS WILL BE VIRTUAL!! + case FW_HYPERCALL_EFI_GET_VARIABLE: + // FIXME: need fixes in efi.h from 2.6.9 + case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE: + case FW_HYPERCALL_EFI_SET_VARIABLE: + case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT: + // FIXME: need fixes in efi.h from 2.6.9 + regs->r8 = EFI_UNSUPPORTED; + break; + case 0xffff: // test dummy hypercall + regs->r8 = dump_privop_counts_to_user( + vcpu_get_gr(v,32), + vcpu_get_gr(v,33)); + break; + case 0xfffe: // test dummy hypercall + regs->r8 = zero_privop_counts_to_user( + vcpu_get_gr(v,32), + vcpu_get_gr(v,33)); + break; + case 0xfffd: // test dummy hypercall + regs->r8 = launch_domainU( + vcpu_get_gr(v,32)); + break; + case 0xfffc: // test dummy hypercall + regs->r8 = domU_staging_write_32( + 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)); + break; + case 0xfffb: // test dummy hypercall + regs->r8 = domU_staging_read_8(vcpu_get_gr(v,32)); + break; + + case __HYPERVISOR_dom0_op: + regs->r8 = do_dom0_op(regs->r14); + break; + + case __HYPERVISOR_dom_mem_op: +#ifdef CONFIG_VTI + regs->r8 = do_dom_mem_op(regs->r14, regs->r15, regs->r16, regs->r17, regs->r18); +#else + /* we don't handle reservations; just return success */ + regs->r8 = regs->r16; +#endif + break; + + case __HYPERVISOR_event_channel_op: + regs->r8 = do_event_channel_op(regs->r14); + break; + +#ifndef CONFIG_VTI + case __HYPERVISOR_grant_table_op: + regs->r8 = do_grant_table_op(regs->r14, regs->r15, regs->r16); + break; +#endif + + case __HYPERVISOR_console_io: + regs->r8 = do_console_io(regs->r14, regs->r15, regs->r16); + break; + + default: + printf("unknown hypercall %x\n", regs->r2); + regs->r8 = (unsigned long)-1; + } + return 1; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/hyperprivop.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/hyperprivop.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1592 @@ +/* + * arch/ia64/kernel/hyperprivop.S + * + * Copyright (C) 2005 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ + +#include <linux/config.h> + +#include <asm/asmmacro.h> +#include <asm/kregs.h> +#include <asm/offsets.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <public/arch-ia64.h> + +#if 1 // change to 0 to turn off all fast paths +#define FAST_HYPERPRIVOPS +#define FAST_HYPERPRIVOP_CNT +#define FAST_REFLECT_CNT +//#define FAST_TICK +#define FAST_BREAK +#define FAST_ACCESS_REFLECT +#define FAST_RFI +#define FAST_SSM_I +#define FAST_PTC_GA +#undef RFI_TO_INTERRUPT // not working yet +#endif + +#ifdef CONFIG_SMP +#warning "FIXME: ptc.ga instruction requires spinlock for SMP" +#undef FAST_PTC_GA +#endif + +// FIXME: turn off for now... but NaTs may crash Xen so re-enable soon! +//#define HANDLE_AR_UNAT + +// FIXME: This is defined in include/asm-ia64/hw_irq.h but this +// doesn't appear to be include'able from assembly? +#define IA64_TIMER_VECTOR 0xef + +// Should be included from common header file (also in process.c) +// NO PSR_CLR IS DIFFERENT! (CPL) +#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT) +#define IA64_PSR_CPL0 (__IA64_UL(1) << IA64_PSR_CPL0_BIT) +// note IA64_PSR_PK removed from following, why is this necessary? +#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \ + IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \ + IA64_PSR_IT | IA64_PSR_BN) + +#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \ + IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \ + IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \ + IA64_PSR_MC | IA64_PSR_IS | \ + IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ + IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) + +// Note: not hand-scheduled for now +// Registers at entry +// r16 == cr.isr +// r17 == cr.iim +// r18 == XSI_PSR_IC_OFS +// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) +// r31 == pr +GLOBAL_ENTRY(fast_hyperprivop) +#ifndef FAST_HYPERPRIVOPS // see beginning of file + br.sptk.many dispatch_break_fault ;; +#endif + // HYPERPRIVOP_SSM_I? + // assumes domain interrupts pending, so just do it + cmp.eq p7,p6=XEN_HYPER_SSM_I,r17 +(p7) br.sptk.many hyper_ssm_i;; + + // FIXME. This algorithm gives up (goes to the slow path) if there + // are ANY interrupts pending, even if they are currently + // undeliverable. This should be improved later... + adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r20=[r20] ;; + cmp.eq p7,p0=r0,r20 +(p7) br.cond.sptk.many 1f + movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r20=[r20];; + adds r21=IA64_VCPU_IRR0_OFFSET,r20; + adds r22=IA64_VCPU_IRR0_OFFSET+8,r20;; + ld8 r23=[r21],16; ld8 r24=[r22],16;; + ld8 r21=[r21]; ld8 r22=[r22];; + or r23=r23,r24; or r21=r21,r22;; + or r20=r23,r21;; +1: // when we get to here r20=~=interrupts pending + + // HYPERPRIVOP_RFI? + cmp.eq p7,p6=XEN_HYPER_RFI,r17 +(p7) br.sptk.many hyper_rfi;; + + // HYPERPRIVOP_GET_IVR? + cmp.eq p7,p6=XEN_HYPER_GET_IVR,r17 +(p7) br.sptk.many hyper_get_ivr;; + + cmp.ne p7,p0=r20,r0 +(p7) br.spnt.many dispatch_break_fault ;; + + // HYPERPRIVOP_COVER? + cmp.eq p7,p6=XEN_HYPER_COVER,r17 +(p7) br.sptk.many hyper_cover;; + + // HYPERPRIVOP_SSM_DT? + cmp.eq p7,p6=XEN_HYPER_SSM_DT,r17 +(p7) br.sptk.many hyper_ssm_dt;; + + // HYPERPRIVOP_RSM_DT? + cmp.eq p7,p6=XEN_HYPER_RSM_DT,r17 +(p7) br.sptk.many hyper_rsm_dt;; + + // HYPERPRIVOP_GET_TPR? + cmp.eq p7,p6=XEN_HYPER_GET_TPR,r17 +(p7) br.sptk.many hyper_get_tpr;; + + // HYPERPRIVOP_SET_TPR? + cmp.eq p7,p6=XEN_HYPER_SET_TPR,r17 +(p7) br.sptk.many hyper_set_tpr;; + + // HYPERPRIVOP_EOI? + cmp.eq p7,p6=XEN_HYPER_EOI,r17 +(p7) br.sptk.many hyper_eoi;; + + // HYPERPRIVOP_SET_ITM? + cmp.eq p7,p6=XEN_HYPER_SET_ITM,r17 +(p7) br.sptk.many hyper_set_itm;; + + // HYPERPRIVOP_SET_RR? + cmp.eq p7,p6=XEN_HYPER_SET_RR,r17 +(p7) br.sptk.many hyper_set_rr;; + + // HYPERPRIVOP_GET_RR? + cmp.eq p7,p6=XEN_HYPER_GET_RR,r17 +(p7) br.sptk.many hyper_get_rr;; + + // HYPERPRIVOP_PTC_GA? + cmp.eq p7,p6=XEN_HYPER_PTC_GA,r17 +(p7) br.sptk.many hyper_ptc_ga;; + + // HYPERPRIVOP_ITC_D? + cmp.eq p7,p6=XEN_HYPER_ITC_D,r17 +(p7) br.sptk.many hyper_itc_d;; + + // HYPERPRIVOP_ITC_I? + cmp.eq p7,p6=XEN_HYPER_ITC_I,r17 +(p7) br.sptk.many hyper_itc_i;; + + // HYPERPRIVOP_THASH? + cmp.eq p7,p6=XEN_HYPER_THASH,r17 +(p7) br.sptk.many hyper_thash;; + + // if not one of the above, give up for now and do it the slow way + br.sptk.many dispatch_break_fault ;; + + +// give up for now if: ipsr.be==1, ipsr.pp==1 +// from reflect_interruption, don't need to: +// - printf first extint (debug only) +// - check for interrupt collection enabled (routine will force on) +// - set ifa (not valid for extint) +// - set iha (not valid for extint) +// - set itir (not valid for extint) +// DO need to +// - increment the HYPER_SSM_I fast_hyperprivop counter +// - set shared_mem iip to instruction after HYPER_SSM_I +// - set cr.iip to guest iva+0x3000 +// - set shared_mem ipsr to [vcpu_get_ipsr_int_state] +// be = pp = bn = 0; dt = it = rt = 1; cpl = 3 or 0; +// i = shared_mem interrupt_delivery_enabled +// ic = shared_mem interrupt_collection_enabled +// ri = instruction after HYPER_SSM_I +// all other bits unchanged from real cr.ipsr +// - set cr.ipsr (DELIVER_PSR_SET/CLEAR, don't forget cpl!) +// - set shared_mem isr: isr.ei to instr following HYPER_SSM_I +// and isr.ri to cr.isr.ri (all other bits zero) +// - cover and set shared_mem precover_ifs to cr.ifs +// ^^^ MISSED THIS FOR fast_break?? +// - set shared_mem ifs and incomplete_regframe to 0 +// - set shared_mem interrupt_delivery_enabled to 0 +// - set shared_mem interrupt_collection_enabled to 0 +// - set r31 to SHAREDINFO_ADDR +// - virtual bank switch 0 +// maybe implement later +// - verify that there really IS a deliverable interrupt pending +// - set shared_mem iva +// needs to be done but not implemented (in reflect_interruption) +// - set shared_mem iipa +// don't know for sure +// - set shared_mem unat +// r16 == cr.isr +// r17 == cr.iim +// r18 == XSI_PSR_IC +// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) +// r31 == pr +ENTRY(hyper_ssm_i) +#ifndef FAST_SSM_I + br.spnt.few dispatch_break_fault ;; +#endif + // give up for now if: ipsr.be==1, ipsr.pp==1 + mov r30=cr.ipsr;; + mov r29=cr.iip;; + extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.sptk.many dispatch_break_fault ;; + extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.sptk.many dispatch_break_fault ;; +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_I);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + // set shared_mem iip to instruction after HYPER_SSM_I + extr.u r20=r30,41,2 ;; + cmp.eq p6,p7=2,r20 ;; +(p6) mov r20=0 +(p6) adds r29=16,r29 +(p7) adds r20=1,r20 ;; + dep r30=r20,r30,41,2;; // adjust cr.ipsr.ri but don't save yet + adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r29 ;; + // set shared_mem isr + extr.u r16=r16,38,1;; // grab cr.isr.ir bit + dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) + dep r16=r20,r16,41,2 ;; // deposit cr.isr.ri + adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r16 ;; + // set cr.ipsr + mov r29=r30 ;; + movl r28=DELIVER_PSR_SET;; + movl r27=~DELIVER_PSR_CLR;; + or r29=r29,r28;; + and r29=r29,r27;; + mov cr.ipsr=r29;; + // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set) + extr.u r29=r30,IA64_PSR_CPL0_BIT,2;; + cmp.eq p6,p7=3,r29;; +(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2 +(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2 + ;; + // FOR SSM_I ONLY, also turn on psr.i and psr.ic + movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT|IA64_PSR_I|IA64_PSR_IC);; + movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);; + or r30=r30,r28;; + and r30=r30,r27;; + adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r30 ;; + // set shared_mem interrupt_delivery_enabled to 0 + // set shared_mem interrupt_collection_enabled to 0 + st8 [r18]=r0;; + // cover and set shared_mem precover_ifs to cr.ifs + // set shared_mem ifs and incomplete_regframe to 0 + cover ;; + mov r20=cr.ifs;; + adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r21]=r0 ;; + adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r0 ;; + adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r20 ;; + // leave cr.ifs alone for later rfi + // set iip to go to domain IVA break instruction vector + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22=[r22];; + adds r22=IA64_VCPU_IVA_OFFSET,r22;; + ld8 r23=[r22];; + movl r24=0x3000;; + add r24=r24,r23;; + mov cr.iip=r24;; + // OK, now all set to go except for switch to virtual bank0 + mov r30=r2; mov r29=r3;; + adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; + adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; + bsw.1;; + // FIXME?: ar.unat is not really handled correctly, + // but may not matter if the OS is NaT-clean + .mem.offset 0,0; st8.spill [r2]=r16,16; + .mem.offset 8,0; st8.spill [r3]=r17,16 ;; + .mem.offset 0,0; st8.spill [r2]=r18,16; + .mem.offset 8,0; st8.spill [r3]=r19,16 ;; + .mem.offset 0,0; st8.spill [r2]=r20,16; + .mem.offset 8,0; st8.spill [r3]=r21,16 ;; + .mem.offset 0,0; st8.spill [r2]=r22,16; + .mem.offset 8,0; st8.spill [r3]=r23,16 ;; + .mem.offset 0,0; st8.spill [r2]=r24,16; + .mem.offset 8,0; st8.spill [r3]=r25,16 ;; + .mem.offset 0,0; st8.spill [r2]=r26,16; + .mem.offset 8,0; st8.spill [r3]=r27,16 ;; + .mem.offset 0,0; st8.spill [r2]=r28,16; + .mem.offset 8,0; st8.spill [r3]=r29,16 ;; + .mem.offset 0,0; st8.spill [r2]=r30,16; + .mem.offset 8,0; st8.spill [r3]=r31,16 ;; + movl r31=XSI_IPSR;; + bsw.0 ;; + mov r2=r30; mov r3=r29;; + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r0 ;; + mov pr=r31,-1 ;; + rfi + ;; + +// reflect domain clock interrupt +// r31 == pr +// r30 == cr.ivr +// r29 == rp +GLOBAL_ENTRY(fast_tick_reflect) +#ifndef FAST_TICK // see beginning of file + br.cond.sptk.many rp;; +#endif + mov r28=IA64_TIMER_VECTOR;; + cmp.ne p6,p0=r28,r30 +(p6) br.cond.spnt.few rp;; + movl r20=THIS_CPU(cpu_info)+IA64_CPUINFO_ITM_NEXT_OFFSET;; + ld8 r26=[r20];; + mov r27=ar.itc;; + adds r27=200,r27;; // safety margin + cmp.ltu p6,p0=r26,r27 +(p6) br.cond.spnt.few rp;; + mov r17=cr.ipsr;; + // slow path if: ipsr.be==1, ipsr.pp==1 + extr.u r21=r17,IA64_PSR_BE_BIT,1 ;; + cmp.ne p6,p0=r21,r0 +(p6) br.cond.spnt.few rp;; + extr.u r21=r17,IA64_PSR_PP_BIT,1 ;; + cmp.ne p6,p0=r21,r0 +(p6) br.cond.spnt.few rp;; + // definitely have a domain tick + mov cr.eoi=r0;; + mov rp=r29;; + mov cr.itm=r26;; // ensure next tick +#ifdef FAST_REFLECT_CNT + movl r20=fast_reflect_count+((0x3000>>8)*8);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + // vcpu_pend_timer(current) + movl r18=XSI_PSR_IC;; + adds r20=XSI_ITV_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r20];; + cmp.eq p6,p0=r20,r0 // if cr.itv==0 done +(p6) br.cond.spnt.few fast_tick_reflect_done;; + tbit.nz p6,p0=r20,16;; // check itv.m (discard) bit +(p6) br.cond.spnt.few fast_tick_reflect_done;; + extr.u r27=r20,0,6 // r27 has low 6 bits of itv.vector + extr.u r26=r20,6,2;; // r26 has irr index of itv.vector + movl r19=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r19=[r19];; + adds r22=IA64_VCPU_DOMAIN_ITM_LAST_OFFSET,r19 + adds r23=IA64_VCPU_DOMAIN_ITM_OFFSET,r19;; + ld8 r24=[r22];; + ld8 r23=[r23];; + cmp.eq p6,p0=r23,r24 // skip if this tick already delivered +(p6) br.cond.spnt.few fast_tick_reflect_done;; + // set irr bit + adds r21=IA64_VCPU_IRR0_OFFSET,r19; + shl r26=r26,3;; + add r21=r21,r26;; + mov r25=1;; + shl r22=r25,r27;; + ld8 r23=[r21];; + or r22=r22,r23;; + st8 [r21]=r22;; + // set PSCB(pending_interruption)! + adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r25;; + + // if interrupted at pl0, we're done + extr.u r16=r17,IA64_PSR_CPL0_BIT,2;; + cmp.eq p6,p0=r16,r0;; +(p6) br.cond.spnt.few fast_tick_reflect_done;; + // if guest vpsr.i is off, we're done + adds r21=XSI_PSR_I_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r21=[r21];; + cmp.eq p6,p0=r21,r0 +(p6) br.cond.spnt.few fast_tick_reflect_done;; + + // OK, we have a clock tick to deliver to the active domain! + // so deliver to iva+0x3000 + // r17 == cr.ipsr + // r18 == XSI_PSR_IC + // r19 == IA64_KR(CURRENT) + // r31 == pr + mov r16=cr.isr;; + mov r29=cr.iip;; + adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r29 ;; + // set shared_mem isr + extr.u r16=r16,38,1;; // grab cr.isr.ir bit + dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) + extr.u r20=r17,41,2 ;; // get ipsr.ri + dep r16=r20,r16,41,2 ;; // deposit cr.isr.ei + adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r16 ;; + // set cr.ipsr (make sure cpl==2!) + mov r29=r17 ;; + movl r28=DELIVER_PSR_SET;; + movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; + or r29=r29,r28;; + and r29=r29,r27;; + mov cr.ipsr=r29;; + // set shared_mem ipsr (from ipsr in r17 with ipsr.ri already set) + extr.u r29=r17,IA64_PSR_CPL0_BIT,2;; + cmp.eq p6,p7=3,r29;; +(p6) dep r17=-1,r17,IA64_PSR_CPL0_BIT,2 +(p7) dep r17=0,r17,IA64_PSR_CPL0_BIT,2 + ;; + movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT);; + movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN|IA64_PSR_I|IA64_PSR_IC);; + dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;; + or r17=r17,r28;; + and r17=r17,r27;; + ld4 r16=[r18],4;; + cmp.ne p6,p0=r16,r0;; +(p6) dep r17=-1,r17,IA64_PSR_IC_BIT,1 ;; + ld4 r16=[r18],-4;; + cmp.ne p6,p0=r16,r0;; +(p6) dep r17=-1,r17,IA64_PSR_I_BIT,1 ;; + adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r17 ;; + // set shared_mem interrupt_delivery_enabled to 0 + // set shared_mem interrupt_collection_enabled to 0 + st8 [r18]=r0;; + // cover and set shared_mem precover_ifs to cr.ifs + // set shared_mem ifs and incomplete_regframe to 0 + cover ;; + mov r20=cr.ifs;; + adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r21]=r0 ;; + adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r0 ;; + adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r20 ;; + // leave cr.ifs alone for later rfi + // set iip to go to domain IVA break instruction vector + adds r22=IA64_VCPU_IVA_OFFSET,r19;; + ld8 r23=[r22];; + movl r24=0x3000;; + add r24=r24,r23;; + mov cr.iip=r24;; + // OK, now all set to go except for switch to virtual bank0 + mov r30=r2; mov r29=r3;; +#ifdef HANDLE_AR_UNAT + mov r28=ar.unat; +#endif + adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; + adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; + bsw.1;; + .mem.offset 0,0; st8.spill [r2]=r16,16; + .mem.offset 8,0; st8.spill [r3]=r17,16 ;; + .mem.offset 0,0; st8.spill [r2]=r18,16; + .mem.offset 8,0; st8.spill [r3]=r19,16 ;; + .mem.offset 0,0; st8.spill [r2]=r20,16; + .mem.offset 8,0; st8.spill [r3]=r21,16 ;; + .mem.offset 0,0; st8.spill [r2]=r22,16; + .mem.offset 8,0; st8.spill [r3]=r23,16 ;; + .mem.offset 0,0; st8.spill [r2]=r24,16; + .mem.offset 8,0; st8.spill [r3]=r25,16 ;; + .mem.offset 0,0; st8.spill [r2]=r26,16; + .mem.offset 8,0; st8.spill [r3]=r27,16 ;; + .mem.offset 0,0; st8.spill [r2]=r28,16; + .mem.offset 8,0; st8.spill [r3]=r29,16 ;; + .mem.offset 0,0; st8.spill [r2]=r30,16; + .mem.offset 8,0; st8.spill [r3]=r31,16 ;; +#ifdef HANDLE_AR_UNAT + // bank0 regs have no NaT bit, so ensure they are NaT clean + mov r16=r0; mov r17=r0; mov r18=r0; mov r19=r0; + mov r20=r0; mov r21=r0; mov r22=r0; mov r23=r0; + mov r24=r0; mov r25=r0; mov r26=r0; mov r27=r0; + mov r28=r0; mov r29=r0; mov r30=r0; movl r31=XSI_IPSR;; +#endif + bsw.0 ;; + mov r2=r30; mov r3=r29;; +#ifdef HANDLE_AR_UNAT + mov ar.unat=r28; +#endif + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r0 ;; +fast_tick_reflect_done: + mov pr=r31,-1 ;; + rfi +END(fast_tick_reflect) + +// reflect domain breaks directly to domain +// r16 == cr.isr +// r17 == cr.iim +// r18 == XSI_PSR_IC +// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) +// r31 == pr +GLOBAL_ENTRY(fast_break_reflect) +#ifndef FAST_BREAK // see beginning of file + br.sptk.many dispatch_break_fault ;; +#endif + mov r30=cr.ipsr;; + mov r29=cr.iip;; + extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; + cmp.ne p7,p0=r21,r0 ;; +(p7) br.spnt.few dispatch_break_fault ;; + extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; + cmp.ne p7,p0=r21,r0 ;; +(p7) br.spnt.few dispatch_break_fault ;; +#if 1 /* special handling in case running on simulator */ + movl r20=first_break;; + ld4 r23=[r20];; + movl r21=0x80001; + movl r22=0x80002;; + cmp.ne p7,p0=r23,r0;; +(p7) br.spnt.few dispatch_break_fault ;; + cmp.eq p7,p0=r21,r17; +(p7) br.spnt.few dispatch_break_fault ;; + cmp.eq p7,p0=r22,r17; +(p7) br.spnt.few dispatch_break_fault ;; +#endif + movl r20=0x2c00; + // save iim in shared_info + adds r21=XSI_IIM_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r17;; + // fall through + + +// reflect to domain ivt+r20 +// sets up isr,iip,ipsr,ifs (FIXME: do iipa too) +// r16 == cr.isr +// r18 == XSI_PSR_IC +// r20 == offset into ivt +// r29 == iip +// r30 == ipsr +// r31 == pr +ENTRY(fast_reflect) +#ifdef FAST_REFLECT_CNT + movl r22=fast_reflect_count; + shr r23=r20,5;; + add r22=r22,r23;; + ld8 r21=[r22];; + adds r21=1,r21;; + st8 [r22]=r21;; +#endif + // save iip in shared_info (DON'T POINT TO NEXT INSTRUCTION!) + adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r29;; + // set shared_mem isr + adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r16 ;; + // set cr.ipsr + mov r29=r30 ;; + movl r28=DELIVER_PSR_SET;; + movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; + or r29=r29,r28;; + and r29=r29,r27;; + mov cr.ipsr=r29;; + // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set) + extr.u r29=r30,IA64_PSR_CPL0_BIT,2;; + cmp.eq p6,p7=3,r29;; +(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2 +(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2 + ;; + movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT);; + movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);; + or r30=r30,r28;; + and r30=r30,r27;; + // also set shared_mem ipsr.i and ipsr.ic appropriately + ld8 r24=[r18];; + extr.u r22=r24,32,32 + cmp4.eq p6,p7=r24,r0;; +(p6) dep r30=0,r30,IA64_PSR_IC_BIT,1 +(p7) dep r30=-1,r30,IA64_PSR_IC_BIT,1 ;; + cmp4.eq p6,p7=r22,r0;; +(p6) dep r30=0,r30,IA64_PSR_I_BIT,1 +(p7) dep r30=-1,r30,IA64_PSR_I_BIT,1 ;; + adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r30 ;; + // set shared_mem interrupt_delivery_enabled to 0 + // set shared_mem interrupt_collection_enabled to 0 + st8 [r18]=r0;; + // cover and set shared_mem precover_ifs to cr.ifs + // set shared_mem ifs and incomplete_regframe to 0 + cover ;; + mov r24=cr.ifs;; + adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r21]=r0 ;; + adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r0 ;; + adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r24 ;; + // vpsr.i = vpsr.ic = 0 on delivery of interruption + st8 [r18]=r0;; + // FIXME: need to save iipa and isr to be arch-compliant + // set iip to go to domain IVA break instruction vector + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22=[r22];; + adds r22=IA64_VCPU_IVA_OFFSET,r22;; + ld8 r23=[r22];; + add r20=r20,r23;; + mov cr.iip=r20;; + // OK, now all set to go except for switch to virtual bank0 + mov r30=r2; mov r29=r3;; +#ifdef HANDLE_AR_UNAT + mov r28=ar.unat; +#endif + adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; + adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; + bsw.1;; + .mem.offset 0,0; st8.spill [r2]=r16,16; + .mem.offset 8,0; st8.spill [r3]=r17,16 ;; + .mem.offset 0,0; st8.spill [r2]=r18,16; + .mem.offset 8,0; st8.spill [r3]=r19,16 ;; + .mem.offset 0,0; st8.spill [r2]=r20,16; + .mem.offset 8,0; st8.spill [r3]=r21,16 ;; + .mem.offset 0,0; st8.spill [r2]=r22,16; + .mem.offset 8,0; st8.spill [r3]=r23,16 ;; + .mem.offset 0,0; st8.spill [r2]=r24,16; + .mem.offset 8,0; st8.spill [r3]=r25,16 ;; + .mem.offset 0,0; st8.spill [r2]=r26,16; + .mem.offset 8,0; st8.spill [r3]=r27,16 ;; + .mem.offset 0,0; st8.spill [r2]=r28,16; + .mem.offset 8,0; st8.spill [r3]=r29,16 ;; + .mem.offset 0,0; st8.spill [r2]=r30,16; + .mem.offset 8,0; st8.spill [r3]=r31,16 ;; +#ifdef HANDLE_AR_UNAT + // bank0 regs have no NaT bit, so ensure they are NaT clean + mov r16=r0; mov r17=r0; mov r18=r0; mov r19=r0; + mov r20=r0; mov r21=r0; mov r22=r0; mov r23=r0; + mov r24=r0; mov r25=r0; mov r26=r0; mov r27=r0; + mov r28=r0; mov r29=r0; mov r30=r0; movl r31=XSI_IPSR;; +#endif + movl r31=XSI_IPSR;; + bsw.0 ;; + mov r2=r30; mov r3=r29;; +#ifdef HANDLE_AR_UNAT + mov ar.unat=r28; +#endif + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r0 ;; + mov pr=r31,-1 ;; + rfi + ;; + +// reflect access faults (0x2400,0x2800,0x5300) directly to domain +// r16 == isr +// r17 == ifa +// r19 == reflect number (only pass-thru to dispatch_reflection) +// r20 == offset into ivt +// r31 == pr +GLOBAL_ENTRY(fast_access_reflect) +#ifndef FAST_ACCESS_REFLECT // see beginning of file + br.spnt.few dispatch_reflection ;; +#endif + mov r30=cr.ipsr;; + mov r29=cr.iip;; + extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + extr.u r21=r30,IA64_PSR_CPL0_BIT,2 ;; + cmp.eq p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + movl r18=XSI_PSR_IC;; + ld8 r21=[r18];; + cmp.eq p7,p0=r0,r21 +(p7) br.spnt.few dispatch_reflection ;; + // set shared_mem ifa, FIXME: should we validate it? + mov r17=cr.ifa;; + adds r21=XSI_IFA_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r17 ;; + // get rr[ifa] and save to itir in shared memory (extra bits ignored) + shr.u r22=r17,61 + adds r23=XSI_ITIR_OFS-XSI_PSR_IC_OFS,r18 + adds r21=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; + shladd r22=r22,3,r21;; + ld8 r22=[r22];; + st8 [r23]=r22;; + br.cond.sptk.many fast_reflect;; + + +// ensure that, if giving up, registers at entry to fast_hyperprivop unchanged +ENTRY(hyper_rfi) +#ifndef FAST_RFI + br.spnt.few dispatch_break_fault ;; +#endif + // if no interrupts pending, proceed + mov r30=r0 + cmp.eq p7,p0=r20,r0 +(p7) br.sptk.many 1f + ;; + adds r20=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r21=[r20];; // r21 = vcr.ipsr + extr.u r22=r21,IA64_PSR_I_BIT,1 ;; + mov r30=r22 + // r30 determines whether we might deliver an immediate extint +1: + adds r20=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r21=[r20];; // r21 = vcr.ipsr + extr.u r22=r21,IA64_PSR_BE_BIT,1 ;; + // if turning on psr.be, give up for now and do it the slow way + cmp.ne p7,p0=r22,r0 +(p7) br.spnt.few dispatch_break_fault ;; + // if (!(vpsr.dt && vpsr.rt && vpsr.it)), do it the slow way + movl r20=(IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_IT);; + and r22=r20,r21 + ;; + cmp.ne p7,p0=r22,r20 +(p7) br.spnt.few dispatch_break_fault ;; + // if was in metaphys mode, do it the slow way (FIXME later?) + adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r20=[r20];; + cmp.ne p7,p0=r20,r0 +(p7) br.spnt.few dispatch_break_fault ;; + // if domain hasn't already done virtual bank switch + // do it the slow way (FIXME later?) +#if 0 + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r20=[r20];; + cmp.eq p7,p0=r20,r0 +(p7) br.spnt.few dispatch_break_fault ;; +#endif + // validate vcr.iip, if in Xen range, do it the slow way + adds r20=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r22=[r20];; + movl r23=XEN_VIRT_SPACE_LOW + movl r24=XEN_VIRT_SPACE_HIGH ;; + cmp.ltu p0,p7=r22,r23 ;; // if !(iip<low) && +(p7) cmp.geu p0,p7=r22,r24 ;; // !(iip>=high) +(p7) br.spnt.few dispatch_break_fault ;; +#ifndef RFI_TO_INTERRUPT // see beginning of file + cmp.ne p6,p0=r30,r0 +(p6) br.cond.spnt.few dispatch_break_fault ;; +#endif + +1: // OK now, let's do an rfi. +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RFI);; + ld8 r23=[r20];; + adds r23=1,r23;; + st8 [r20]=r23;; +#endif +#ifdef RFI_TO_INTERRUPT + // maybe do an immediate interrupt delivery? + cmp.ne p6,p0=r30,r0 +(p6) br.cond.spnt.few rfi_check_extint;; +#endif + +just_do_rfi: + // r18=&vpsr.i|vpsr.ic, r21==vpsr, r22=vcr.iip + mov cr.iip=r22;; + adds r20=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r0 ;; + adds r20=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r20];; + dep r20=0,r20,38,25;; // ensure ifs has no reserved bits set + mov cr.ifs=r20 ;; + // ipsr.cpl == (vcr.ipsr.cpl == 0) 2 : 3; + dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;; + // vpsr.i = vcr.ipsr.i; vpsr.ic = vcr.ipsr.ic + mov r19=r0 ;; + extr.u r23=r21,IA64_PSR_I_BIT,1 ;; + cmp.ne p7,p6=r23,r0 ;; + // not done yet +(p7) dep r19=-1,r19,32,1 + extr.u r23=r21,IA64_PSR_IC_BIT,1 ;; + cmp.ne p7,p6=r23,r0 ;; +(p7) dep r19=-1,r19,0,1 ;; + st8 [r18]=r19 ;; + // force on psr.ic, i, dt, rt, it, bn + movl r20=(IA64_PSR_I|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_IT|IA64_PSR_BN) + ;; + or r21=r21,r20 + ;; + mov cr.ipsr=r21 + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r21=[r20];; + cmp.ne p7,p0=r21,r0 // domain already did "bank 1 switch?" +(p7) br.cond.spnt.few 1f; + // OK, now all set to go except for switch to virtual bank1 + mov r22=1;; st4 [r20]=r22; + mov r30=r2; mov r29=r3;; + adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; + adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; + bsw.1;; + // FIXME?: ar.unat is not really handled correctly, + // but may not matter if the OS is NaT-clean + .mem.offset 0,0; ld8.fill r16=[r2],16 ; + .mem.offset 8,0; ld8.fill r17=[r3],16 ;; + .mem.offset 0,0; ld8.fill r18=[r2],16 ; + .mem.offset 0,0; ld8.fill r19=[r3],16 ;; + .mem.offset 8,0; ld8.fill r20=[r2],16 ; + .mem.offset 8,0; ld8.fill r21=[r3],16 ;; + .mem.offset 8,0; ld8.fill r22=[r2],16 ; + .mem.offset 8,0; ld8.fill r23=[r3],16 ;; + .mem.offset 8,0; ld8.fill r24=[r2],16 ; + .mem.offset 8,0; ld8.fill r25=[r3],16 ;; + .mem.offset 8,0; ld8.fill r26=[r2],16 ; + .mem.offset 8,0; ld8.fill r27=[r3],16 ;; + .mem.offset 8,0; ld8.fill r28=[r2],16 ; + .mem.offset 8,0; ld8.fill r29=[r3],16 ;; + .mem.offset 8,0; ld8.fill r30=[r2],16 ; + .mem.offset 8,0; ld8.fill r31=[r3],16 ;; + bsw.0 ;; + mov r2=r30; mov r3=r29;; +1: mov pr=r31,-1 + ;; + rfi + ;; + +#ifdef RFI_TO_INTERRUPT +GLOBAL_ENTRY(rfi_check_extint) + //br.sptk.many dispatch_break_fault ;; + + // r18=&vpsr.i|vpsr.ic, r21==vpsr, r22=vcr.iip + // make sure none of these get trashed in case going to just_do_rfi + movl r30=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r30=[r30];; + adds r24=IA64_VCPU_INSVC3_OFFSET,r30;; + mov r25=192 + adds r16=IA64_VCPU_IRR3_OFFSET,r30;; + ld8 r23=[r16];; + cmp.eq p6,p0=r23,r0;; +(p6) adds r16=-8,r16;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r16];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r16=-8,r16;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r16];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r16=-8,r16;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r16];; +(p6) cmp.eq p6,p0=r23,r0;; + cmp.eq p6,p0=r23,r0 +(p6) br.cond.spnt.few just_do_rfi; // this is actually an error + // r16 points to non-zero element of irr, r23 has value + // r24 points to corr element of insvc, r25 has elt*64 + ld8 r26=[r24];; + cmp.geu p6,p0=r26,r23 +(p6) br.cond.spnt.many just_do_rfi; + + // not masked by insvc, get vector number + shr.u r26=r23,1;; + or r26=r23,r26;; + shr.u r27=r26,2;; + or r26=r26,r27;; + shr.u r27=r26,4;; + or r26=r26,r27;; + shr.u r27=r26,8;; + or r26=r26,r27;; + shr.u r27=r26,16;; + or r26=r26,r27;; + shr.u r27=r26,32;; + or r26=r26,r27;; + andcm r26=0xffffffffffffffff,r26;; + popcnt r26=r26;; + sub r26=63,r26;; + // r26 now contains the bit index (mod 64) + mov r27=1;; + shl r27=r27,r26;; + // r27 now contains the (within the proper word) bit mask + add r26=r25,r26 + // r26 now contains the vector [0..255] + adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r20] ;; + extr.u r28=r20,16,1 + extr.u r29=r20,4,4 ;; + cmp.ne p6,p0=r28,r0 // if tpr.mmi is set, just rfi +(p6) br.cond.spnt.few just_do_rfi;; + shl r29=r29,4;; + adds r29=15,r29;; + cmp.ge p6,p0=r29,r26 // if tpr masks interrupt, just rfi +(p6) br.cond.spnt.few just_do_rfi;; + +// this doesn't work yet (dies early after getting to user mode) +// but happens relatively infrequently, so fix it later. +// NOTE that these will be counted incorrectly for now (for privcnt output) +GLOBAL_ENTRY(rfi_with_interrupt) +#if 1 + br.sptk.many dispatch_break_fault ;; +#endif + + // OK, have an unmasked vector, so deliver extint to vcr.iva+0x3000 + // r18 == XSI_PSR_IC + // r21 == vipsr (ipsr in shared_mem) + // r30 == IA64_KR(CURRENT) + // r31 == pr + mov r17=cr.ipsr;; + mov r16=cr.isr;; + // set shared_mem isr + extr.u r16=r16,38,1;; // grab cr.isr.ir bit + dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) + extr.u r20=r21,41,2 ;; // get v(!)psr.ri + dep r16=r20,r16,41,2 ;; // deposit cr.isr.ei + adds r22=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r22]=r16 ;; + // set cr.ipsr (make sure cpl==2!) + mov r29=r17 ;; + movl r28=DELIVER_PSR_SET;; + movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; + or r29=r29,r28;; + and r29=r29,r27;; + mov cr.ipsr=r29;; + // v.ipsr and v.iip are already set (and v.iip validated) as rfi target + // set shared_mem interrupt_delivery_enabled to 0 + // set shared_mem interrupt_collection_enabled to 0 + st8 [r18]=r0;; + // cover and set shared_mem precover_ifs to cr.ifs + // set shared_mem ifs and incomplete_regframe to 0 +#if 0 + cover ;; + mov r20=cr.ifs;; + adds r22=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r22]=r0 ;; + adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r22]=r0 ;; + adds r22=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r22]=r20 ;; + // leave cr.ifs alone for later rfi +#else + adds r22=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r22]=r0 ;; + adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r22];; + st8 [r22]=r0 ;; + adds r22=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r22]=r20 ;; +#endif + // set iip to go to domain IVA break instruction vector + adds r22=IA64_VCPU_IVA_OFFSET,r30;; + ld8 r23=[r22];; + movl r24=0x3000;; + add r24=r24,r23;; + mov cr.iip=r24;; +#if 0 + // OK, now all set to go except for switch to virtual bank0 + mov r30=r2; mov r29=r3;; + adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; + adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; + bsw.1;; + // FIXME: need to handle ar.unat! + .mem.offset 0,0; st8.spill [r2]=r16,16; + .mem.offset 8,0; st8.spill [r3]=r17,16 ;; + .mem.offset 0,0; st8.spill [r2]=r18,16; + .mem.offset 8,0; st8.spill [r3]=r19,16 ;; + .mem.offset 0,0; st8.spill [r2]=r20,16; + .mem.offset 8,0; st8.spill [r3]=r21,16 ;; + .mem.offset 0,0; st8.spill [r2]=r22,16; + .mem.offset 8,0; st8.spill [r3]=r23,16 ;; + .mem.offset 0,0; st8.spill [r2]=r24,16; + .mem.offset 8,0; st8.spill [r3]=r25,16 ;; + .mem.offset 0,0; st8.spill [r2]=r26,16; + .mem.offset 8,0; st8.spill [r3]=r27,16 ;; + .mem.offset 0,0; st8.spill [r2]=r28,16; + .mem.offset 8,0; st8.spill [r3]=r29,16 ;; + .mem.offset 0,0; st8.spill [r2]=r30,16; + .mem.offset 8,0; st8.spill [r3]=r31,16 ;; + movl r31=XSI_IPSR;; + bsw.0 ;; + mov r2=r30; mov r3=r29;; +#else + bsw.1;; + movl r31=XSI_IPSR;; + bsw.0 ;; +#endif + adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; + st4 [r20]=r0 ;; + mov pr=r31,-1 ;; + rfi +#endif // RFI_TO_INTERRUPT + +ENTRY(hyper_cover) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_COVER);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r24=cr.ipsr + mov r25=cr.iip;; + // skip test for vpsr.ic.. it's a prerequisite for hyperprivops + cover ;; + adds r20=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; + mov r30=cr.ifs;; + adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 + ld4 r21=[r20] ;; + cmp.eq p6,p7=r21,r0 ;; +(p6) st8 [r22]=r30;; +(p7) st4 [r20]=r0;; + mov cr.ifs=r0;; + // adjust return address to skip over break instruction + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; + +// return from metaphysical mode (meta=1) to virtual mode (meta=0) +ENTRY(hyper_ssm_dt) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_DT);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r24=cr.ipsr + mov r25=cr.iip;; + adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r21=[r20];; + cmp.eq p7,p0=r21,r0 // meta==0? +(p7) br.spnt.many 1f ;; // already in virtual mode + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22=[r22];; + adds r22=IA64_VCPU_META_SAVED_RR0_OFFSET,r22;; + ld4 r23=[r22];; + mov rr[r0]=r23;; + srlz.i;; + st4 [r20]=r0 ;; + // adjust return address to skip over break instruction +1: extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; + +// go to metaphysical mode (meta=1) from virtual mode (meta=0) +ENTRY(hyper_rsm_dt) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RSM_DT);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r24=cr.ipsr + mov r25=cr.iip;; + adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; + ld4 r21=[r20];; + cmp.ne p7,p0=r21,r0 // meta==0? +(p7) br.spnt.many 1f ;; // already in metaphysical mode + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22=[r22];; + adds r22=IA64_VCPU_META_RR0_OFFSET,r22;; + ld4 r23=[r22];; + mov rr[r0]=r23;; + srlz.i;; + adds r21=1,r0 ;; + st4 [r20]=r21 ;; + // adjust return address to skip over break instruction +1: extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; + +ENTRY(hyper_get_tpr) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_TPR);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r24=cr.ipsr + mov r25=cr.iip;; + adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r8=[r20];; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_get_tpr) + +// if we get to here, there are no interrupts pending so we +// can change virtual tpr to any value without fear of provoking +// (or accidentally missing) delivering an interrupt +ENTRY(hyper_set_tpr) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_TPR);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r24=cr.ipsr + mov r25=cr.iip;; + movl r27=0xff00;; + adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; + andcm r8=r8,r27;; + st8 [r20]=r8;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_set_tpr) + +ENTRY(hyper_get_ivr) +#ifdef FAST_HYPERPRIVOP_CNT + movl r22=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_IVR);; + ld8 r21=[r22];; + adds r21=1,r21;; + st8 [r22]=r21;; +#endif + mov r8=15;; + // when we get to here r20=~=interrupts pending + cmp.eq p7,p0=r20,r0;; +(p7) adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; +(p7) st4 [r20]=r0;; +(p7) br.spnt.many 1f ;; + movl r30=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r30=[r30];; + adds r24=IA64_VCPU_INSVC3_OFFSET,r30;; + mov r25=192 + adds r22=IA64_VCPU_IRR3_OFFSET,r30;; + ld8 r23=[r22];; + cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) adds r24=-8,r24;; +(p6) adds r25=-64,r25;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; + cmp.eq p6,p0=r23,r0 +(p6) br.cond.spnt.few 1f; // this is actually an error + // r22 points to non-zero element of irr, r23 has value + // r24 points to corr element of insvc, r25 has elt*64 + ld8 r26=[r24];; + cmp.geu p6,p0=r26,r23 +(p6) br.cond.spnt.many 1f; + // not masked by insvc, get vector number + shr.u r26=r23,1;; + or r26=r23,r26;; + shr.u r27=r26,2;; + or r26=r26,r27;; + shr.u r27=r26,4;; + or r26=r26,r27;; + shr.u r27=r26,8;; + or r26=r26,r27;; + shr.u r27=r26,16;; + or r26=r26,r27;; + shr.u r27=r26,32;; + or r26=r26,r27;; + andcm r26=0xffffffffffffffff,r26;; + popcnt r26=r26;; + sub r26=63,r26;; + // r26 now contains the bit index (mod 64) + mov r27=1;; + shl r27=r27,r26;; + // r27 now contains the (within the proper word) bit mask + add r26=r25,r26 + // r26 now contains the vector [0..255] + adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r20] ;; + extr.u r28=r20,16,1 + extr.u r29=r20,4,4 ;; + cmp.ne p6,p0=r28,r0 // if tpr.mmi is set, return SPURIOUS +(p6) br.cond.spnt.few 1f; + shl r29=r29,4;; + adds r29=15,r29;; + cmp.ge p6,p0=r29,r26 +(p6) br.cond.spnt.few 1f; + // OK, have an unmasked vector to process/return + ld8 r25=[r24];; + or r25=r25,r27;; + st8 [r24]=r25;; + ld8 r25=[r22];; + andcm r25=r25,r27;; + st8 [r22]=r25;; + mov r8=r26;; + // if its a clock tick, remember itm to avoid delivering it twice + adds r20=XSI_ITV_OFS-XSI_PSR_IC_OFS,r18 ;; + ld8 r20=[r20];; + extr.u r20=r20,0,8;; + cmp.eq p6,p0=r20,r8 + adds r22=IA64_VCPU_DOMAIN_ITM_LAST_OFFSET,r30 + adds r23=IA64_VCPU_DOMAIN_ITM_OFFSET,r30;; + ld8 r23=[r23];; +(p6) st8 [r22]=r23;; + // all done +1: mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_get_ivr) + +ENTRY(hyper_eoi) + // when we get to here r20=~=interrupts pending + cmp.ne p7,p0=r20,r0 +(p7) br.spnt.many dispatch_break_fault ;; +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_EOI);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22=[r22];; + adds r22=IA64_VCPU_INSVC3_OFFSET,r22;; + ld8 r23=[r22];; + cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; +(p6) adds r22=-8,r22;; +(p6) ld8 r23=[r22];; +(p6) cmp.eq p6,p0=r23,r0;; + cmp.eq p6,p0=r23,r0 +(p6) br.cond.spnt.few 1f; // this is actually an error + // r22 points to non-zero element of insvc, r23 has value + shr.u r24=r23,1;; + or r24=r23,r24;; + shr.u r25=r24,2;; + or r24=r24,r25;; + shr.u r25=r24,4;; + or r24=r24,r25;; + shr.u r25=r24,8;; + or r24=r24,r25;; + shr.u r25=r24,16;; + or r24=r24,r25;; + shr.u r25=r24,32;; + or r24=r24,r25;; + andcm r24=0xffffffffffffffff,r24;; + popcnt r24=r24;; + sub r24=63,r24;; + // r24 now contains the bit index + mov r25=1;; + shl r25=r25,r24;; + andcm r23=r23,r25;; + st8 [r22]=r23;; +1: mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_eoi) + +ENTRY(hyper_set_itm) + // when we get to here r20=~=interrupts pending + cmp.ne p7,p0=r20,r0 +(p7) br.spnt.many dispatch_break_fault ;; +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_ITM);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + movl r20=THIS_CPU(cpu_info)+IA64_CPUINFO_ITM_NEXT_OFFSET;; + ld8 r21=[r20];; + movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r20=[r20];; + adds r20=IA64_VCPU_DOMAIN_ITM_OFFSET,r20;; + st8 [r20]=r8;; + cmp.geu p6,p0=r21,r8;; +(p6) mov r21=r8;; + // now "safe set" cr.itm=r21 + mov r23=100;; +2: mov cr.itm=r21;; + srlz.d;; + mov r22=ar.itc ;; + cmp.leu p6,p0=r21,r22;; + add r21=r21,r23;; + shl r23=r23,1;; +(p6) br.cond.spnt.few 2b;; +1: mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_set_itm) + +ENTRY(hyper_get_rr) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_RR);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + extr.u r25=r8,61,3;; + adds r20=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; + shl r25=r25,3;; + add r20=r20,r25;; + ld8 r8=[r20];; +1: mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_get_rr) + +ENTRY(hyper_set_rr) + extr.u r25=r8,61,3;; + cmp.leu p7,p0=7,r25 // punt on setting rr7 +(p7) br.spnt.many dispatch_break_fault ;; +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_RR);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + extr.u r26=r9,8,24 // r26 = r9.rid + movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r20=[r20];; + adds r21=IA64_VCPU_STARTING_RID_OFFSET,r20;; + ld4 r22=[r21];; + adds r21=IA64_VCPU_ENDING_RID_OFFSET,r20;; + ld4 r23=[r21];; + adds r24=IA64_VCPU_META_SAVED_RR0_OFFSET,r20;; + add r22=r26,r22;; + cmp.geu p6,p0=r22,r23 // if r9.rid + starting_rid >= ending_rid +(p6) br.cond.spnt.few 1f; // this is an error, but just ignore/return + // r21=starting_rid + adds r20=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; + shl r25=r25,3;; + add r20=r20,r25;; + st8 [r20]=r9;; // store away exactly what was passed + // but adjust value actually placed in rr[r8] + // r22 contains adjusted rid, "mangle" it (see regionreg.c) + // and set ps to PAGE_SHIFT and ve to 1 + extr.u r27=r22,0,8 + extr.u r28=r22,8,8 + extr.u r29=r22,16,8;; + dep.z r23=PAGE_SHIFT,2,6;; + dep r23=-1,r23,0,1;; // mangling is swapping bytes 1 & 3 + dep r23=r27,r23,24,8;; + dep r23=r28,r23,16,8;; + dep r23=r29,r23,8,8 + cmp.eq p6,p0=r25,r0;; // if rr0, save for metaphysical +(p6) st4 [r24]=r23 + mov rr[r8]=r23;; + // done, mosey on back +1: mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_set_rr) + +// this routine was derived from optimized assembly output from +// vcpu_thash so it is dense and difficult to read but it works +// On entry: +// r18 == XSI_PSR_IC +// r31 == pr +GLOBAL_ENTRY(hyper_thash) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_THASH);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + shr.u r20 = r8, 61 + addl r25 = 1, r0 + movl r17 = 0xe000000000000000 + ;; + and r21 = r17, r8 // VHPT_Addr1 + ;; + shladd r28 = r20, 3, r18 + adds r19 = XSI_PTA_OFS-XSI_PSR_IC_OFS, r18 + ;; + adds r27 = XSI_RR0_OFS-XSI_PSR_IC_OFS, r28 + addl r28 = 32767, r0 + ld8 r24 = [r19] // pta + ;; + ld8 r23 = [r27] // rrs[vadr>>61] + extr.u r26 = r24, 2, 6 + ;; + extr.u r22 = r23, 2, 6 + shl r30 = r25, r26 + ;; + shr.u r19 = r8, r22 + shr.u r29 = r24, 15 + ;; + adds r17 = -1, r30 + ;; + shladd r27 = r19, 3, r0 + extr.u r26 = r17, 15, 46 + ;; + andcm r24 = r29, r26 + and r19 = r28, r27 + shr.u r25 = r27, 15 + ;; + and r23 = r26, r25 + ;; + or r22 = r24, r23 + ;; + dep.z r20 = r22, 15, 46 + ;; + or r16 = r20, r21 + ;; + or r8 = r19, r16 + // done, update iip/ipsr to next instruction + mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_thash) + +ENTRY(hyper_ptc_ga) +#ifndef FAST_PTC_GA + br.spnt.few dispatch_break_fault ;; +#endif + // FIXME: validate not flushing Xen addresses +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_PTC_GA);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r28=r8 + extr.u r19=r9,2,6 // addr_range=1<<((r9&0xfc)>>2) + mov r20=1 + shr.u r24=r8,61 + addl r27=56,r0 // PAGE_SHIFT<<2 (for ptc.ga) + movl r26=0x8000000000000000 // INVALID_TI_TAG + mov r30=ar.lc + ;; + shl r19=r20,r19 + cmp.eq p7,p0=7,r24 +(p7) br.spnt.many dispatch_break_fault ;; // slow way for rr7 + ;; + cmp.le p7,p0=r19,r0 // skip flush if size<=0 +(p7) br.cond.dpnt 2f ;; + extr.u r24=r19,0,PAGE_SHIFT + shr.u r23=r19,PAGE_SHIFT ;; // repeat loop for n pages + cmp.ne p7,p0=r24,r0 ;; +(p7) adds r23=1,r23 ;; // n_pages<size<n_pages+1? extra iter + mov ar.lc=r23 + movl r29=PAGE_SIZE;; +1: + thash r25=r28 ;; + adds r25=16,r25 ;; + ld8 r24=[r25] ;; + // FIXME: should check if tag matches, not just blow it away + or r24=r26,r24 ;; // vhpt_entry->ti_tag = 1 + st8 [r25]=r24 + ptc.ga r28,r27 ;; + srlz.i ;; + add r28=r29,r28 + br.cloop.sptk.few 1b + ;; +2: + mov ar.lc=r30 ;; + mov r29=cr.ipsr + mov r30=cr.iip;; + movl r27=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r27=[r27];; + adds r25=IA64_VCPU_DTLB_OFFSET,r27 + adds r26=IA64_VCPU_ITLB_OFFSET,r27;; + ld8 r24=[r25] + ld8 r27=[r26] ;; + and r24=-2,r24 + and r27=-2,r27 ;; + st8 [r25]=r24 // set 1-entry i/dtlb as not present + st8 [r26]=r27 ;; + // increment to point to next instruction + extr.u r26=r29,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r30=16,r30 +(p7) adds r26=1,r26 + ;; + dep r29=r26,r29,41,2 + ;; + mov cr.ipsr=r29 + mov cr.iip=r30 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_ptc_ga) + +ENTRY(hyper_itc_d) + br.spnt.many dispatch_break_fault ;; +END(hyper_itc_d) + +ENTRY(hyper_itc_i) + br.spnt.many dispatch_break_fault ;; +END(hyper_itc_i) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/idle0_task.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/idle0_task.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,58 @@ +#include <xen/config.h> +#include <xen/sched.h> +#include <asm/desc.h> + +#define INIT_MM(name) \ +{ \ + .pgd = swapper_pg_dir, \ + .mm_users = ATOMIC_INIT(2), \ + .mm_count = ATOMIC_INIT(1), \ + .page_table_lock = SPIN_LOCK_UNLOCKED, \ + .mmlist = LIST_HEAD_INIT(name.mmlist), \ +} + +#define IDLE0_EXEC_DOMAIN(_ed,_d) \ +{ \ + processor: 0, \ + mm: 0, \ + thread: INIT_THREAD, \ + domain: (_d) \ +} + +#define IDLE0_DOMAIN(_t) \ +{ \ + domain_id: IDLE_DOMAIN_ID, \ + domain_flags:DOMF_idle_domain, \ + refcnt: ATOMIC_INIT(1) \ +} + +struct mm_struct init_mm = INIT_MM(init_mm); +EXPORT_SYMBOL(init_mm); + +struct domain idle0_domain = IDLE0_DOMAIN(idle0_domain); +#if 0 +struct vcpu idle0_vcpu = IDLE0_EXEC_DOMAIN(idle0_vcpu, + &idle0_domain); +#endif + + +/* + * Initial task structure. + * + * We need to make sure that this is properly aligned due to the way process stacks are + * handled. This is done by having a special ".data.init_task" section... + */ +union { + struct { + struct domain task; + } s; + unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)]; +} init_task_mem asm ("init_task") __attribute__((section(".data.init_task"))); +// = {{ + ; +//.task = IDLE0_EXEC_DOMAIN(init_task_mem.s.task,&idle0_domain), +//}; +//}; + +EXPORT_SYMBOL(init_task); + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/irq.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/irq.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1503 @@ +/* + * linux/arch/ia64/kernel/irq.c + * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + * + * Copyright (C) Ashok Raj<ashok.raj@xxxxxxxxx>, Intel Corporation 2004 + * + * 4/14/2004: Added code to handle cpu migration and do safe irq + * migration without lossing interrupts for iosapic + * architecture. + */ + +/* + * (mostly architecture independent, will move to kernel/irq.c in 2.5.) + * + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/module.h> +#ifndef XEN +#include <linux/signal.h> +#endif +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <linux/slab.h> +#ifndef XEN +#include <linux/random.h> +#include <linux/cpu.h> +#endif +#include <linux/ctype.h> +#ifndef XEN +#include <linux/smp_lock.h> +#endif +#include <linux/init.h> +#ifndef XEN +#include <linux/kernel_stat.h> +#endif +#include <linux/irq.h> +#ifndef XEN +#include <linux/proc_fs.h> +#endif +#include <linux/seq_file.h> +#ifndef XEN +#include <linux/kallsyms.h> +#include <linux/notifier.h> +#endif + +#include <asm/atomic.h> +#ifndef XEN +#include <asm/cpu.h> +#endif +#include <asm/io.h> +#include <asm/smp.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/pgalloc.h> +#ifndef XEN +#include <asm/tlbflush.h> +#endif +#include <asm/delay.h> +#include <asm/irq.h> + +#ifdef XEN +#include <xen/event.h> +#define _irq_desc irq_desc +#define irq_descp(irq) &irq_desc[irq] +#define apicid_to_phys_cpu_present(x) 1 +#endif + + +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the appropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .status = IRQ_DISABLED, + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; + +/* + * This is updated when the user sets irq affinity via /proc + */ +cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; + +#ifdef CONFIG_IA64_GENERIC +irq_desc_t * __ia64_irq_desc (unsigned int irq) +{ + return _irq_desc + irq; +} + +ia64_vector __ia64_irq_to_vector (unsigned int irq) +{ + return (ia64_vector) irq; +} + +unsigned int __ia64_local_vector_to_irq (ia64_vector vec) +{ + return (unsigned int) vec; +} +#endif + +static void register_irq_proc (unsigned int irq); + +/* + * Special irq handlers. + */ + +#ifdef XEN +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +#else +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ return IRQ_NONE; } +#endif + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesn't deserve + * a generic callback i think. + */ +#ifdef CONFIG_X86 + printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N + * irq slots per priority level, and a 'hanging, unacked' IRQ + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. + */ + ack_APIC_irq(); +#endif +#endif +#ifdef CONFIG_IA64 + printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); +#endif +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +atomic_t irq_err_count; +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG +atomic_t irq_mis_count; +#endif +#endif + +/* + * Generic, controller-independent functions: + */ + +#ifndef XEN +int show_interrupts(struct seq_file *p, void *v) +{ + int j, i = *(loff_t *) v; + struct irqaction * action; + irq_desc_t *idesc; + unsigned long flags; + + if (i == 0) { + seq_puts(p, " "); + for (j=0; j<NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } + + if (i < NR_IRQS) { + idesc = irq_descp(i); + spin_lock_irqsave(&idesc->lock, flags); + action = idesc->action; + if (!action) + goto skip; + seq_printf(p, "%3d: ",i); +#ifndef CONFIG_SMP + seq_printf(p, "%10u ", kstat_irqs(i)); +#else + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); +#endif + seq_printf(p, " %14s", idesc->handler->typename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + + seq_putc(p, '\n'); +skip: + spin_unlock_irqrestore(&idesc->lock, flags); + } else if (i == NR_IRQS) { + seq_puts(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); +#ifdef CONFIG_X86_LOCAL_APIC + seq_puts(p, "LOC: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_putc(p, '\n'); +#endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +#endif +#endif + } + return 0; +} +#endif + +#ifdef CONFIG_SMP +inline void synchronize_irq(unsigned int irq) +{ +#ifndef XEN + struct irq_desc *desc = irq_desc + irq; + + while (desc->status & IRQ_INPROGRESS) + cpu_relax(); +#endif +} +EXPORT_SYMBOL(synchronize_irq); +#endif + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, + struct pt_regs *regs, struct irqaction *action) +{ + int status = 1; /* Force the "do bottom halves" bit */ + int retval = 0; + +#ifndef XEN + if (!(action->flags & SA_INTERRUPT)) +#endif + local_irq_enable(); + +#ifdef XEN + action->handler(irq, action->dev_id, regs); +#else + do { + status |= action->flags; + retval |= action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); +#endif + local_irq_disable(); + return retval; +} + +#ifndef XEN +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; + + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} +#endif + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +#ifndef XEN +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); + } + + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; +} +#endif + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +inline void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_descp(irq); + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} +EXPORT_SYMBOL(disable_irq_nosync); + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_descp(irq); + + disable_irq_nosync(irq); + if (desc->action) + synchronize_irq(irq); +} +EXPORT_SYMBOL(disable_irq); + +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_descp(irq); + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; +#ifndef XEN + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } +#endif + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk(KERN_ERR "enable_irq(%u) unbalanced from %p\n", + irq, (void *) __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} +EXPORT_SYMBOL(enable_irq); + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) +{ + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; + +#ifndef XEN + kstat_this_cpu.irqs[irq]++; +#endif + if (desc->status & IRQ_PER_CPU) { + irqreturn_t action_ret; + + /* + * No locking required for CPU-local interrupts: + */ + desc->handler->ack(irq); + action_ret = handle_IRQ_event(irq, regs, desc->action); +#ifndef XEN + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); +#endif + desc->handler->end(irq); + return 1; + } + + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + * REPLAY is when Linux resends an IRQ that was dropped earlier + * WAITING is used by probe to mark irqs that are being tested + */ +#ifdef XEN + status = desc->status & ~IRQ_REPLAY; +#else + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); +#endif + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + * Since we set PENDING, if another processor is handling + * a different instance of this same irq, the other processor + * will take care of it. + */ + if (unlikely(!action)) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + irqreturn_t action_ret; + + spin_unlock(&desc->lock); + + action_ret = handle_IRQ_event(irq, regs, action); + + spin_lock(&desc->lock); +#ifndef XEN + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); +#endif + if (likely(!(desc->status & IRQ_PENDING))) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + return 1; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk(KERN_ERR "Bad boy: %s called us without a dev_id!\n", devname); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = xmalloc(struct irqaction); + if (!action) + return -ENOMEM; + + action->handler = handler; +#ifndef XEN + action->flags = irqflags; + action->mask = 0; +#endif + action->name = devname; +#ifndef XEN + action->next = NULL; +#endif + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + xfree(action); + return retval; +} + +EXPORT_SYMBOL(request_irq); + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function must not be called from interrupt context. + */ + +#ifdef XEN +void free_irq(unsigned int irq) +#else +void free_irq(unsigned int irq, void *dev_id) +#endif +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_descp(irq); + spin_lock_irqsave(&desc->lock,flags); +#ifdef XEN + if (desc->action) { + struct irqaction * action = desc->action; + desc->action = NULL; +#else + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { +#endif + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); +#ifndef XEN + } +#endif + spin_unlock_irqrestore(&desc->lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + synchronize_irq(irq); + xfree(action); + return; + } + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); +#ifndef XEN + return; + } +#endif +} + +EXPORT_SYMBOL(free_irq); + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +#ifndef XEN +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_descp(i); + + spin_lock_irq(&desc->lock); + if (!desc->action) + desc->handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ barrier(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_descp(i); + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ barrier(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_descp(i); + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +EXPORT_SYMBOL(probe_irq_on); + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < 16; i++) { + irq_desc_t *desc = irq_descp(i); + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; +} +EXPORT_SYMBOL(probe_irq_mask); + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldn't happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_descp(i); + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +EXPORT_SYMBOL(probe_irq_off); +#endif + +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_descp(irq); + +#ifndef XEN + if (desc->handler == &no_irq_type) + return -ENOSYS; + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + if (new->flags & SA_PERCPU_IRQ) { + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_ia64_lsapic; + } +#endif + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { +#ifdef XEN + if (1) { + /* Can't share interrupts unless both agree to */ +#else + if (!(old->flags & new->flags & SA_SHIRQ)) { +#endif + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + +#ifndef XEN + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; +#endif + } + + *p = new; + +#ifndef XEN + if (!shared) { +#else + { +#endif + desc->depth = 0; +#ifdef XEN + desc->status &= ~(IRQ_DISABLED | IRQ_INPROGRESS); +#else + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); +#endif + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + +#ifndef XEN + register_irq_proc(irq); +#endif + return 0; +} + +#ifndef XEN + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; + +#ifdef CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; + +static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; + +void set_irq_affinity_info (unsigned int irq, int hwid, int redir) +{ + cpumask_t mask = CPU_MASK_NONE; + + cpu_set(cpu_logical_id(hwid), mask); + + if (irq < NR_IRQS) { + irq_affinity[irq] = mask; + irq_redir[irq] = (char) (redir & 0xff); + } +} + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = sprintf(page, "%s", irq_redir[(long)data] ? "r " : ""); + + len += cpumask_scnprintf(page+len, count, irq_affinity[(long)data]); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned int irq = (unsigned long) data; + int full_count = count, err; + cpumask_t new_value, tmp; +# define R_PREFIX_LEN 16 + char rbuf[R_PREFIX_LEN]; + int rlen; + int prelen; + irq_desc_t *desc = irq_descp(irq); + unsigned long flags; + + if (!desc->handler->set_affinity) + return -EIO; + + /* + * If string being written starts with a prefix of 'r' or 'R' + * and some limited number of spaces, set IA64_IRQ_REDIRECTED. + * If more than (R_PREFIX_LEN - 2) spaces are passed, they won't + * all be trimmed as part of prelen, the untrimmed spaces will + * cause the hex parsing to fail, and this write() syscall will + * fail with EINVAL. + */ + + if (!count) + return -EINVAL; + rlen = min(sizeof(rbuf)-1, count); + if (copy_from_user(rbuf, buffer, rlen)) + return -EFAULT; + rbuf[rlen] = 0; + prelen = 0; + if (tolower(*rbuf) == 'r') { + prelen = strspn(rbuf, "Rr "); + irq |= IA64_IRQ_REDIRECTED; + } + + err = cpumask_parse(buffer+prelen, count-prelen, new_value); + if (err) + return err; + + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + cpus_and(tmp, new_value, cpu_online_map); + if (cpus_empty(tmp)) + return -EINVAL; + + spin_lock_irqsave(&desc->lock, flags); + pending_irq_cpumask[irq] = new_value; + spin_unlock_irqrestore(&desc->lock, flags); + + return full_count; +} + +void move_irq(int irq) +{ + /* note - we hold desc->lock */ + cpumask_t tmp; + irq_desc_t *desc = irq_descp(irq); + + if (!cpus_empty(pending_irq_cpumask[irq])) { + cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); + if (unlikely(!cpus_empty(tmp))) { + desc->handler->set_affinity(irq, pending_irq_cpumask[irq]); + } + cpus_clear(pending_irq_cpumask[irq]); + } +} + + +#endif /* CONFIG_SMP */ +#endif + +#ifdef CONFIG_HOTPLUG_CPU +unsigned int vectors_in_migration[NR_IRQS]; + +/* + * Since cpu_online_map is already updated, we just need to check for + * affinity that has zeros + */ +static void migrate_irqs(void) +{ + cpumask_t mask; + irq_desc_t *desc; + int irq, new_cpu; + + for (irq=0; irq < NR_IRQS; irq++) { + desc = irq_descp(irq); + + /* + * No handling for now. + * TBD: Implement a disable function so we can now + * tell CPU not to respond to these local intr sources. + * such as ITV,CPEI,MCA etc. + */ + if (desc->status == IRQ_PER_CPU) + continue; + + cpus_and(mask, irq_affinity[irq], cpu_online_map); + if (any_online_cpu(mask) == NR_CPUS) { + /* + * Save it for phase 2 processing + */ + vectors_in_migration[irq] = irq; + + new_cpu = any_online_cpu(cpu_online_map); + mask = cpumask_of_cpu(new_cpu); + + /* + * Al three are essential, currently WARN_ON.. maybe panic? + */ + if (desc->handler && desc->handler->disable && + desc->handler->enable && desc->handler->set_affinity) { + desc->handler->disable(irq); + desc->handler->set_affinity(irq, mask); + desc->handler->enable(irq); + } else { + WARN_ON((!(desc->handler) || !(desc->handler->disable) || + !(desc->handler->enable) || + !(desc->handler->set_affinity))); + } + } + } +} + +void fixup_irqs(void) +{ + unsigned int irq; + extern void ia64_process_pending_intr(void); + + ia64_set_itv(1<<16); + /* + * Phase 1: Locate irq's bound to this cpu and + * relocate them for cpu removal. + */ + migrate_irqs(); + + /* + * Phase 2: Perform interrupt processing for all entries reported in + * local APIC. + */ + ia64_process_pending_intr(); + + /* + * Phase 3: Now handle any interrupts not captured in local APIC. + * This is to account for cases that device interrupted during the time the + * rte was being disabled and re-programmed. + */ + for (irq=0; irq < NR_IRQS; irq++) { + if (vectors_in_migration[irq]) { + vectors_in_migration[irq]=0; + do_IRQ(irq, NULL); + } + } + + /* + * Now let processor die. We do irq disable and max_xtp() to + * ensure there is no more interrupts routed to this processor. + * But the local timer interrupt can have 1 pending which we + * take care in timer_interrupt(). + */ + max_xtp(); + local_irq_disable(); +} +#endif + +#ifndef XEN +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + cpumask_t *mask = (cpumask_t *)data; + unsigned long full_count = count, err; + cpumask_t new_value; + + err = cpumask_parse(buffer, count, new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_descp(irq)->handler == &no_irq_type) || irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + +#ifdef CONFIG_SMP + { + struct proc_dir_entry *entry; + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif +} + +cpumask_t prof_cpu_mask = CPU_MASK_ALL; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_descp(i)->handler == &no_irq_type) + continue; + register_irq_proc(i); + } +} +#endif + + +#ifdef XEN +/* + * HANDLING OF GUEST-BOUND PHYSICAL IRQS + */ + +#define IRQ_MAX_GUESTS 7 +typedef struct { + u8 nr_guests; + u8 in_flight; + u8 shareable; + struct domain *guest[IRQ_MAX_GUESTS]; +} irq_guest_action_t; + +static void __do_IRQ_guest(int irq) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action = (irq_guest_action_t *)desc->action; + struct domain *d; + int i; + + for ( i = 0; i < action->nr_guests; i++ ) + { + d = action->guest[i]; + if ( !test_and_set_bit(irq, &d->pirq_mask) ) + action->in_flight++; + send_guest_pirq(d, irq); + } +} + +int pirq_guest_unmask(struct domain *d) +{ + irq_desc_t *desc; + int i, j, pirq; + u32 m; + shared_info_t *s = d->shared_info; + + for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ ) + { + m = d->pirq_mask[i]; + while ( (j = ffs(m)) != 0 ) + { + m &= ~(1 << --j); + pirq = (i << 5) + j; + desc = &irq_desc[pirq]; + spin_lock_irq(&desc->lock); + if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) && + test_and_clear_bit(pirq, &d->pirq_mask) && + (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) + desc->handler->end(pirq); + spin_unlock_irq(&desc->lock); + } + } + + return 0; +} + +int pirq_guest_bind(struct vcpu *d, int irq, int will_share) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action; + unsigned long flags; + int rc = 0; + + if ( !IS_CAPABLE_PHYSDEV(d->domain) ) + return -EPERM; + + spin_lock_irqsave(&desc->lock, flags); + + action = (irq_guest_action_t *)desc->action; + + if ( !(desc->status & IRQ_GUEST) ) + { + if ( desc->action != NULL ) + { + DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n", + irq, desc->action->name); + rc = -EBUSY; + goto out; + } + + action = xmalloc(irq_guest_action_t); + if ( (desc->action = (struct irqaction *)action) == NULL ) + { + DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq); + rc = -ENOMEM; + goto out; + } + + action->nr_guests = 0; + action->in_flight = 0; + action->shareable = will_share; + + desc->depth = 0; + desc->status |= IRQ_GUEST; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); + + /* Attempt to bind the interrupt target to the correct CPU. */ +#if 0 /* FIXME CONFIG_SMP ??? */ + if ( desc->handler->set_affinity != NULL ) + desc->handler->set_affinity( + irq, apicid_to_phys_cpu_present(d->processor)); +#endif + } + else if ( !will_share || !action->shareable ) + { + DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n", + irq); + rc = -EBUSY; + goto out; + } + + if ( action->nr_guests == IRQ_MAX_GUESTS ) + { + DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq); + rc = -EBUSY; + goto out; + } + + action->guest[action->nr_guests++] = d; + + out: + spin_unlock_irqrestore(&desc->lock, flags); + return rc; +} + +int pirq_guest_unbind(struct domain *d, int irq) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action; + unsigned long flags; + int i; + + spin_lock_irqsave(&desc->lock, flags); + + action = (irq_guest_action_t *)desc->action; + + if ( test_and_clear_bit(irq, &d->pirq_mask) && + (--action->in_flight == 0) ) + desc->handler->end(irq); + + if ( action->nr_guests == 1 ) + { + desc->action = NULL; + xfree(action); + desc->depth = 1; + desc->status |= IRQ_DISABLED; + desc->status &= ~IRQ_GUEST; + desc->handler->shutdown(irq); + } + else + { + i = 0; + while ( action->guest[i] != d ) + i++; + memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1); + action->nr_guests--; + } + + spin_unlock_irqrestore(&desc->lock, flags); + return 0; +} + +#endif + +#ifdef XEN +#ifdef IA64 +// this is a temporary hack until real console input is implemented +irqreturn_t guest_forward_keyboard_input(int irq, void *nada, struct pt_regs *regs) +{ + domain_pend_keyboard_interrupt(irq); +} + +void serial_input_init(void) +{ + int retval; + int irq = 0x30; // FIXME + + retval = request_irq(irq,guest_forward_keyboard_input,SA_INTERRUPT,"siminput",NULL); + if (retval) { + printk("serial_input_init: broken request_irq call\n"); + while(1); + } +} +#endif +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/ivt.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/ivt.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1975 @@ + +#ifdef XEN +//#define CONFIG_DISABLE_VHPT // FIXME: change when VHPT is enabled?? +// these are all hacked out for now as the entire IVT +// will eventually be replaced... just want to use it +// for startup code to handle TLB misses +//#define ia64_leave_kernel 0 +//#define ia64_ret_from_syscall 0 +//#define ia64_handle_irq 0 +//#define ia64_fault 0 +#define ia64_illegal_op_fault 0 +#define ia64_prepare_handle_unaligned 0 +#define ia64_bad_break 0 +#define ia64_trace_syscall 0 +#define sys_call_table 0 +#define sys_ni_syscall 0 +#include <asm/vhpt.h> +#endif +/* + * arch/ia64/kernel/ivt.S + * + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co + * Stephane Eranian <eranian@xxxxxxxxxx> + * David Mosberger <davidm@xxxxxxxxxx> + * Copyright (C) 2000, 2002-2003 Intel Co + * Asit Mallick <asit.k.mallick@xxxxxxxxx> + * Suresh Siddha <suresh.b.siddha@xxxxxxxxx> + * Kenneth Chen <kenneth.w.chen@xxxxxxxxx> + * Fenghua Yu <fenghua.yu@xxxxxxxxx> + * + * 00/08/23 Asit Mallick <asit.k.mallick@xxxxxxxxx> TLB handling for SMP + * 00/12/20 David Mosberger-Tang <davidm@xxxxxxxxxx> DTLB/ITLB handler now uses virtual PT. + */ +/* + * This file defines the interruption vector table used by the CPU. + * It does not include one entry per possible cause of interruption. + * + * The first 20 entries of the table contain 64 bundles each while the + * remaining 48 entries contain only 16 bundles each. + * + * The 64 bundles are used to allow inlining the whole handler for critical + * interruptions like TLB misses. + * + * For each entry, the comment is as follows: + * + * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + * entry offset ----/ / / / / + * entry number ---------/ / / / + * size of the entry -------------/ / / + * vector name -------------------------------------/ / + * interruptions triggering this vector ----------------------/ + * + * The table is 32KB in size and must be aligned on 32KB boundary. + * (The CPU ignores the 15 lower bits of the address) + * + * Table is based upon EAS2.6 (Oct 1999) + */ + +#include <linux/config.h> + +#include <asm/asmmacro.h> +#include <asm/break.h> +#include <asm/ia32.h> +#include <asm/kregs.h> +#include <asm/offsets.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/thread_info.h> +#include <asm/unistd.h> +#include <asm/errno.h> + +#if 1 +# define PSR_DEFAULT_BITS psr.ac +#else +# define PSR_DEFAULT_BITS 0 +#endif + +#if 0 + /* + * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't + * needed for something else before enabling this... + */ +# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 +#else +# define DBG_FAULT(i) +#endif + +#define MINSTATE_VIRT /* needed by minstate.h */ +#include "minstate.h" + +#define FAULT(n) \ + mov r31=pr; \ + mov r19=n;; /* prepare to save predicates */ \ + br.sptk.many dispatch_to_fault_handler + +#ifdef XEN +#define REFLECT(n) \ + mov r31=pr; \ + mov r19=n;; /* prepare to save predicates */ \ + br.sptk.many dispatch_reflection +#endif + + .section .text.ivt,"ax" + + .align 32768 // align on 32KB boundary + .global ia64_ivt +ia64_ivt: +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) +ENTRY(vhpt_miss) + DBG_FAULT(0) + /* + * The VHPT vector is invoked when the TLB entry for the virtual page table + * is missing. This happens only as a result of a previous + * (the "original") TLB miss, which may either be caused by an instruction + * fetch or a data access (or non-access). + * + * What we do here is normal TLB miss handing for the _original_ miss, followed + * by inserting the TLB entry for the virtual page table page that the VHPT + * walker was attempting to access. The latter gets inserted as long + * as both L1 and L2 have valid mappings for the faulting address. + * The TLB entry for the original miss gets inserted only if + * the L3 entry indicates that the page is present. + * + * do_page_fault gets invoked in the following cases: + * - the faulting virtual address uses unimplemented address bits + * - the faulting virtual address has no L1, L2, or L3 mapping + */ + mov r16=cr.ifa // get address that caused the TLB miss +#ifdef CONFIG_HUGETLB_PAGE + movl r18=PAGE_SHIFT + mov r25=cr.itir +#endif + ;; + rsm psr.dt // use physical addressing for data + mov r31=pr // save the predicate registers +#ifdef XEN + movl r19=THIS_CPU(cpu_kr)+IA64_KR_PT_BASE_OFFSET;; +#else + mov r19=IA64_KR(PT_BASE) // get page table base address +#endif + shl r21=r16,3 // shift bit 60 into sign bit + shr.u r17=r16,61 // get the region number into r17 + ;; + shr r22=r21,3 +#ifdef CONFIG_HUGETLB_PAGE + extr.u r26=r25,2,6 + ;; + cmp.ne p8,p0=r18,r26 + sub r27=r26,r18 + ;; +(p8) dep r25=r18,r25,2,6 +(p8) shr r22=r22,r27 +#endif + ;; + cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? + shr.u r18=r22,PGDIR_SHIFT // get bits 33-63 of the faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + + srlz.d + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 +(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT +(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 + ;; +(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + cmp.eq p7,p6=0,r21 // unused address bits all zeroes? + shr.u r18=r22,PMD_SHIFT // shift L2 index into position + ;; + ld8 r17=[r17] // fetch the L1 entry (may be 0) + ;; +(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; +(p7) ld8 r20=[r17] // fetch the L2 entry (may be 0) + shr.u r19=r22,PAGE_SHIFT // shift L3 index into position + ;; +(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L2 entry NULL? + dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L3 page table entry + ;; +(p7) ld8 r18=[r21] // read the L3 PTE + mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss + ;; +(p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared? + mov r22=cr.iha // get the VHPT address that caused the TLB miss + ;; // avoid RAW on p7 +(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? + dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address + ;; +(p10) itc.i r18 // insert the instruction TLB entry +(p11) itc.d r18 // insert the data TLB entry +(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) + mov cr.ifa=r22 + +#ifdef CONFIG_HUGETLB_PAGE +(p8) mov cr.itir=r25 // change to default page-size for VHPT +#endif + + /* + * Now compute and insert the TLB entry for the virtual page table. We never + * execute in a page table page so there is no need to set the exception deferral + * bit. + */ + adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 + ;; +(p7) itc.d r24 + ;; +#ifdef CONFIG_SMP + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + + /* + * Re-check L2 and L3 pagetable. If they changed, we may have received a ptc.g + * between reading the pagetable and the "itc". If so, flush the entry we + * inserted and retry. + */ + ld8 r25=[r21] // read L3 PTE again + ld8 r26=[r17] // read L2 entry again + ;; + cmp.ne p6,p7=r26,r20 // did L2 entry change + mov r27=PAGE_SHIFT<<2 + ;; +(p6) ptc.l r22,r27 // purge PTE page translation +(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did L3 PTE change + ;; +(p6) ptc.l r16,r27 // purge translation +#endif + + mov pr=r31,-1 // restore predicate registers + rfi +END(vhpt_miss) + + .org ia64_ivt+0x400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0400 Entry 1 (size 64 bundles) ITLB (21) +ENTRY(itlb_miss) + DBG_FAULT(1) +#ifdef XEN + VHPT_CCHAIN_LOOKUP(itlb_miss,i) +#ifdef VHPT_GLOBAL + br.cond.sptk page_fault + ;; +#endif +#endif + /* + * The ITLB handler accesses the L3 PTE via the virtually mapped linear + * page table. If a nested TLB miss occurs, we switch into physical + * mode, walk the page table, and then re-execute the L3 PTE read + * and go on normally after that. + */ + mov r16=cr.ifa // get virtual address + mov r29=b0 // save b0 + mov r31=pr // save predicates +.itlb_fault: + mov r17=cr.iha // get virtual address of L3 PTE + movl r30=1f // load nested fault continuation point + ;; +1: ld8 r18=[r17] // read L3 PTE + ;; + mov b0=r29 + tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? +(p6) br.cond.spnt page_fault + ;; + itc.i r18 + ;; +#ifdef CONFIG_SMP + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + + ld8 r19=[r17] // read L3 PTE again and see if same + mov r20=PAGE_SHIFT<<2 // setup page size for purge + ;; + cmp.ne p7,p0=r18,r19 + ;; +(p7) ptc.l r16,r20 +#endif + mov pr=r31,-1 + rfi +END(itlb_miss) + + .org ia64_ivt+0x0800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) +ENTRY(dtlb_miss) + DBG_FAULT(2) +#ifdef XEN + VHPT_CCHAIN_LOOKUP(dtlb_miss,d) +#ifdef VHPT_GLOBAL + br.cond.sptk page_fault + ;; +#endif +#endif + /* + * The DTLB handler accesses the L3 PTE via the virtually mapped linear + * page table. If a nested TLB miss occurs, we switch into physical + * mode, walk the page table, and then re-execute the L3 PTE read + * and go on normally after that. + */ + mov r16=cr.ifa // get virtual address + mov r29=b0 // save b0 + mov r31=pr // save predicates +dtlb_fault: + mov r17=cr.iha // get virtual address of L3 PTE + movl r30=1f // load nested fault continuation point + ;; +1: ld8 r18=[r17] // read L3 PTE + ;; + mov b0=r29 + tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? +(p6) br.cond.spnt page_fault + ;; + itc.d r18 + ;; +#ifdef CONFIG_SMP + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + + ld8 r19=[r17] // read L3 PTE again and see if same + mov r20=PAGE_SHIFT<<2 // setup page size for purge + ;; + cmp.ne p7,p0=r18,r19 + ;; +(p7) ptc.l r16,r20 +#endif + mov pr=r31,-1 + rfi +END(dtlb_miss) + + .org ia64_ivt+0x0c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) +ENTRY(alt_itlb_miss) + DBG_FAULT(3) +#ifdef XEN +//#ifdef VHPT_GLOBAL +// VHPT_CCHAIN_LOOKUP(alt_itlb_miss,i) +// br.cond.sptk page_fault +// ;; +//#endif +#endif +#ifdef XEN + mov r31=pr + mov r16=cr.ifa // get address that caused the TLB miss + ;; +late_alt_itlb_miss: + movl r17=PAGE_KERNEL + mov r21=cr.ipsr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + ;; +#else + mov r16=cr.ifa // get address that caused the TLB miss + movl r17=PAGE_KERNEL + mov r21=cr.ipsr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + mov r31=pr + ;; +#endif +#ifdef CONFIG_DISABLE_VHPT + shr.u r22=r16,61 // get the region number into r21 + ;; + cmp.gt p8,p0=6,r22 // user mode + ;; +(p8) thash r17=r16 + ;; +(p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 +(p8) br.cond.dptk .itlb_fault +#endif + extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits +#ifdef XEN + shr.u r18=r16,55 // move address bit 59 to bit 4 + ;; + and r18=0x10,r18 // bit 4=address-bit(59) +#else + shr.u r18=r16,57 // move address bit 61 to bit 4 + ;; + andcm r18=0x10,r18 // bit 4=~address-bit(61) +#endif + cmp.ne p8,p0=r0,r23 // psr.cpl != 0? + or r19=r17,r19 // insert PTE control bits into r19 + ;; + or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 +(p8) br.cond.spnt page_fault + ;; + itc.i r19 // insert the TLB entry + mov pr=r31,-1 + rfi +END(alt_itlb_miss) + + .org ia64_ivt+0x1000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) +ENTRY(alt_dtlb_miss) + DBG_FAULT(4) +#ifdef XEN +//#ifdef VHPT_GLOBAL +// VHPT_CCHAIN_LOOKUP(alt_dtlb_miss,d) +// br.cond.sptk page_fault +// ;; +//#endif +#endif +#ifdef XEN + mov r31=pr + mov r16=cr.ifa // get address that caused the TLB miss + ;; +late_alt_dtlb_miss: + movl r17=PAGE_KERNEL + mov r20=cr.isr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + mov r21=cr.ipsr + ;; +#else +#endif +#ifdef CONFIG_DISABLE_VHPT + shr.u r22=r16,61 // get the region number into r21 + ;; + cmp.gt p8,p0=6,r22 // access to region 0-5 + ;; +(p8) thash r17=r16 + ;; +(p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 +(p8) br.cond.dptk dtlb_fault +#endif + extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl + and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field + tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? +#ifdef XEN + shr.u r18=r16,55 // move address bit 59 to bit 4 + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits + tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? + ;; + and r18=0x10,r18 // bit 4=address-bit(59) +#else + shr.u r18=r16,57 // move address bit 61 to bit 4 + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits + tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? + ;; + andcm r18=0x10,r18 // bit 4=~address-bit(61) +#endif + cmp.ne p8,p0=r0,r23 +(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field +(p8) br.cond.spnt page_fault +#ifdef XEN + ;; + // Test for Xen address, if not handle via page_fault + // note that 0xf000 (cached) and 0xe800 (uncached) addresses + // should be OK. + extr.u r22=r16,59,5;; + cmp.eq p8,p0=0x1e,r22 +(p8) br.cond.spnt 1f;; + cmp.ne p8,p0=0x1d,r22 +(p8) br.cond.sptk page_fault ;; +1: +#endif + + dep r21=-1,r21,IA64_PSR_ED_BIT,1 + or r19=r19,r17 // insert PTE control bits into r19 + ;; + or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 +(p6) mov cr.ipsr=r21 + ;; +(p7) itc.d r19 // insert the TLB entry + mov pr=r31,-1 + rfi +END(alt_dtlb_miss) + + .org ia64_ivt+0x1400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) +ENTRY(nested_dtlb_miss) + /* + * In the absence of kernel bugs, we get here when the virtually mapped linear + * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction + * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page + * table is missing, a nested TLB miss fault is triggered and control is + * transferred to this point. When this happens, we lookup the pte for the + * faulting address by walking the page table in physical mode and return to the + * continuation point passed in register r30 (or call page_fault if the address is + * not mapped). + * + * Input: r16: faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Output: r17: physical address of L3 PTE of faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Clobbered: b0, r18, r19, r21, psr.dt (cleared) + */ + rsm psr.dt // switch to using physical data addressing +#ifdef XEN + movl r19=THIS_CPU(cpu_kr)+IA64_KR_PT_BASE_OFFSET;; +#else + mov r19=IA64_KR(PT_BASE) // get the page table base address +#endif + shl r21=r16,3 // shift bit 60 into sign bit + ;; + shr.u r17=r16,61 // get the region number into r17 + ;; + cmp.eq p6,p7=5,r17 // is faulting address in region 5? + shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + + srlz.d + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 +(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT +(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 + ;; +(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + cmp.eq p7,p6=0,r21 // unused address bits all zeroes? + shr.u r18=r16,PMD_SHIFT // shift L2 index into position + ;; + ld8 r17=[r17] // fetch the L1 entry (may be 0) + ;; +(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; +(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) + shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + ;; +(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? + dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry +(p6) br.cond.spnt page_fault + mov b0=r30 + br.sptk.many b0 // return to continuation point +END(nested_dtlb_miss) + + .org ia64_ivt+0x1800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) +ENTRY(ikey_miss) +#ifdef XEN + REFLECT(6) +#endif + DBG_FAULT(6) + FAULT(6) +END(ikey_miss) + + //----------------------------------------------------------------------------------- + // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address) +ENTRY(page_fault) + ssm psr.dt + ;; + srlz.i + ;; + SAVE_MIN_WITH_COVER +#ifdef XEN + alloc r15=ar.pfs,0,0,4,0 + mov out0=cr.ifa + mov out1=cr.isr + mov out3=cr.itir +#else + alloc r15=ar.pfs,0,0,3,0 + mov out0=cr.ifa + mov out1=cr.isr +#endif + adds r3=8,r2 // set up second base pointer + ;; + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collectin is on + ;; +(p15) ssm psr.i // restore psr.i + movl r14=ia64_leave_kernel + ;; + SAVE_REST + mov rp=r14 + ;; + adds out2=16,r12 // out2 = pointer to pt_regs + br.call.sptk.many b6=ia64_do_page_fault // ignore return address +END(page_fault) + + .org ia64_ivt+0x1c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) +ENTRY(dkey_miss) +#ifdef XEN + REFLECT(7) +#endif + DBG_FAULT(7) + FAULT(7) +END(dkey_miss) + + .org ia64_ivt+0x2000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) +ENTRY(dirty_bit) +#ifdef XEN + REFLECT(8) +#endif + DBG_FAULT(8) + /* + * What we do here is to simply turn on the dirty bit in the PTE. We need to + * update both the page-table and the TLB entry. To efficiently access the PTE, + * we address it through the virtual page table. Most likely, the TLB entry for + * the relevant virtual page table page is still present in the TLB so we can + * normally do this without additional TLB misses. In case the necessary virtual + * page table TLB entry isn't present, we take a nested TLB miss hit where we look + * up the physical address of the L3 PTE and then continue at label 1 below. + */ + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r29=b0 // save b0 in case of nested fault + mov r31=pr // save pr +#ifdef CONFIG_SMP + mov r28=ar.ccv // save ar.ccv + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.d r25 // install updated PTE + ;; + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov b0=r29 // restore b0 + mov ar.ccv=r28 +#else + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + or r18=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits + mov b0=r29 // restore b0 + ;; + st8 [r17]=r18 // store back updated PTE + itc.d r18 // install updated PTE +#endif + mov pr=r31,-1 // restore pr + rfi +END(dirty_bit) + + .org ia64_ivt+0x2400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) +ENTRY(iaccess_bit) +#ifdef XEN + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=9 + movl r20=0x2400 + br.sptk.many fast_access_reflect;; +#endif + DBG_FAULT(9) + // Like Entry 8, except for instruction access + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + mov r31=pr // save predicates +#ifdef CONFIG_ITANIUM + /* + * Erratum 10 (IFA may contain incorrect address) has "NoFix" status. + */ + mov r17=cr.ipsr + ;; + mov r18=cr.iip + tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set? + ;; +(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa +#endif /* CONFIG_ITANIUM */ + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r29=b0 // save b0 in case of nested fault) +#ifdef CONFIG_SMP + mov r28=ar.ccv // save ar.ccv + ;; +1: ld8 r18=[r17] + ;; + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_A,r18 // set the accessed bit + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.i r25 // install updated PTE + ;; + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov b0=r29 // restore b0 + mov ar.ccv=r28 +#else /* !CONFIG_SMP */ + ;; +1: ld8 r18=[r17] + ;; + or r18=_PAGE_A,r18 // set the accessed bit + mov b0=r29 // restore b0 + ;; + st8 [r17]=r18 // store back updated PTE + itc.i r18 // install updated PTE +#endif /* !CONFIG_SMP */ + mov pr=r31,-1 + rfi +END(iaccess_bit) + + .org ia64_ivt+0x2800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) +ENTRY(daccess_bit) +#ifdef XEN + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=10 + movl r20=0x2800 + br.sptk.many fast_access_reflect;; +#endif + DBG_FAULT(10) + // Like Entry 8, except for data access + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r31=pr + mov r29=b0 // save b0 in case of nested fault) +#ifdef CONFIG_SMP + mov r28=ar.ccv // save ar.ccv + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + mov ar.ccv=r18 // set compare value for cmpxchg + or r25=_PAGE_A,r18 // set the dirty bit + ;; + cmpxchg8.acq r26=[r17],r25,ar.ccv + mov r24=PAGE_SHIFT<<2 + ;; + cmp.eq p6,p7=r26,r18 + ;; +(p6) itc.d r25 // install updated PTE + /* + * Tell the assemblers dependency-violation checker that the above "itc" instructions + * cannot possibly affect the following loads: + */ + dv_serialize_data + ;; + ld8 r18=[r17] // read PTE again + ;; + cmp.eq p6,p7=r18,r25 // is it same as the newly installed + ;; +(p7) ptc.l r16,r24 + mov ar.ccv=r28 +#else + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + or r18=_PAGE_A,r18 // set the accessed bit + ;; + st8 [r17]=r18 // store back updated PTE + itc.d r18 // install updated PTE +#endif + mov b0=r29 // restore b0 + mov pr=r31,-1 + rfi +END(daccess_bit) + + .org ia64_ivt+0x2c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) +ENTRY(break_fault) + /* + * The streamlined system call entry/exit paths only save/restore the initial part + * of pt_regs. This implies that the callers of system-calls must adhere to the + * normal procedure calling conventions. + * + * Registers to be saved & restored: + * CR registers: cr.ipsr, cr.iip, cr.ifs + * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr + * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15 + * Registers to be restored only: + * r8-r11: output value from the system call. + * + * During system call exit, scratch registers (including r15) are modified/cleared + * to prevent leaking bits from kernel to user level. + */ + DBG_FAULT(11) +#ifdef XEN + mov r16=cr.isr + mov r17=cr.iim + mov r31=pr + ;; + movl r18=XSI_PSR_IC + ;; + ld8 r19=[r18] + ;; + cmp.eq p7,p0=r0,r17 // is this a psuedo-cover? +(p7) br.spnt.many dispatch_privop_fault + ;; + // if vpsr.ic is off, we have a hyperprivop + // A hyperprivop is hand-coded assembly with psr.ic off + // which means no calls, no use of r1-r15 and no memory accesses + // except to pinned addresses! + cmp4.eq p7,p0=r0,r19 +(p7) br.sptk.many fast_hyperprivop + ;; + movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r22 = [r22] + ;; + adds r22=IA64_VCPU_BREAKIMM_OFFSET,r22;; + ld4 r23=[r22];; + cmp4.eq p6,p7=r23,r17 // Xen-reserved breakimm? +(p6) br.spnt.many dispatch_break_fault + ;; + br.sptk.many fast_break_reflect + ;; +#endif + movl r16=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; + ld8 r16=[r16] + mov r17=cr.iim + mov r18=__IA64_BREAK_SYSCALL + mov r21=ar.fpsr + mov r29=cr.ipsr + mov r19=b6 + mov r25=ar.unat + mov r27=ar.rsc + mov r26=ar.pfs + mov r28=cr.iip +#ifndef XEN + mov r31=pr // prepare to save predicates +#endif + mov r20=r1 + ;; + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 + cmp.eq p0,p7=r18,r17 // is this a system call? (p7 <- false, if so) +(p7) br.cond.spnt non_syscall + ;; + ld1 r17=[r16] // load current->thread.on_ustack flag + st1 [r16]=r0 // clear current->thread.on_ustack flag + add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT + ;; + invala + + /* adjust return address so we skip over the break instruction: */ + + extr.u r8=r29,41,2 // extract ei field from cr.ipsr + ;; + cmp.eq p6,p7=2,r8 // isr.ei==2? + mov r2=r1 // setup r2 for ia64_syscall_setup + ;; +(p6) mov r8=0 // clear ei to 0 +(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped +(p7) adds r8=1,r8 // increment ei to next slot + ;; + cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already? + dep r29=r8,r29,41,2 // insert new ei into cr.ipsr + ;; + + // switch from user to kernel RBS: + MINSTATE_START_SAVE_MIN_VIRT + br.call.sptk.many b7=ia64_syscall_setup + ;; + MINSTATE_END_SAVE_MIN_VIRT // switch to bank 1 + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + mov r3=NR_syscalls - 1 + ;; +(p15) ssm psr.i // restore psr.i + // p10==true means out registers are more than 8 or r15's Nat is true +(p10) br.cond.spnt.many ia64_ret_from_syscall + ;; + movl r16=sys_call_table + + adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + movl r2=ia64_ret_from_syscall + ;; + shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) + cmp.leu p6,p7=r15,r3 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? + mov rp=r2 // set the real return addr + ;; +(p6) ld8 r20=[r20] // load address of syscall entry point +(p7) movl r20=sys_ni_syscall + + add r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 r2=[r2] // r2 = current_thread_info()->flags + ;; + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit + ;; + cmp.eq p8,p0=r2,r0 + mov b6=r20 + ;; +(p8) br.call.sptk.many b6=b6 // ignore this return addr + br.cond.sptk ia64_trace_syscall + // NOT REACHED +END(break_fault) + + .org ia64_ivt+0x3000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) +ENTRY(interrupt) + DBG_FAULT(12) + mov r31=pr // prepare to save predicates + ;; +#ifdef XEN + mov r30=cr.ivr // pass cr.ivr as first arg + // FIXME: this is a hack... use cpuinfo.ksoftirqd because its + // not used anywhere else and we need a place to stash ivr and + // there's no registers available unused by SAVE_MIN/REST + movl r29=THIS_CPU(cpu_info)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; + st8 [r29]=r30;; + movl r28=slow_interrupt;; + mov r29=rp;; + mov rp=r28;; + br.cond.sptk.many fast_tick_reflect + ;; +slow_interrupt: + mov rp=r29;; +#endif + SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 + ssm psr.ic | PSR_DEFAULT_BITS + ;; + adds r3=8,r2 // set up second base pointer for SAVE_REST + srlz.i // ensure everybody knows psr.ic is back on + ;; + SAVE_REST + ;; + alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group +#ifdef XEN + movl out0=THIS_CPU(cpu_info)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; + ld8 out0=[out0];; +#else + mov out0=cr.ivr // pass cr.ivr as first arg +#endif + add out1=16,sp // pass pointer to pt_regs as second arg + ;; + srlz.d // make sure we see the effect of cr.ivr + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.call.sptk.many b6=ia64_handle_irq +END(interrupt) + + .org ia64_ivt+0x3400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3400 Entry 13 (size 64 bundles) Reserved + DBG_FAULT(13) + FAULT(13) + +#ifdef XEN + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + +GLOBAL_ENTRY(dispatch_break_fault) + SAVE_MIN_WITH_COVER + ;; +dispatch_break_fault_post_save: + alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + mov out2=cr.isr // FIXME: pity to make this slow access twice + mov out3=cr.iim // FIXME: pity to make this slow access twice + + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.sptk.many ia64_prepare_handle_break +END(dispatch_break_fault) +#endif + + .org ia64_ivt+0x3800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3800 Entry 14 (size 64 bundles) Reserved + DBG_FAULT(14) + FAULT(14) + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + * + * ia64_syscall_setup() is a separate subroutine so that it can + * allocate stacked registers so it can safely demine any + * potential NaT values from the input registers. + * + * On entry: + * - executing on bank 0 or bank 1 register set (doesn't matter) + * - r1: stack pointer + * - r2: current task pointer + * - r3: preserved + * - r11: original contents (saved ar.pfs to be saved) + * - r12: original contents (sp to be saved) + * - r13: original contents (tp to be saved) + * - r15: original contents (syscall # to be saved) + * - r18: saved bsp (after switching to kernel stack) + * - r19: saved b6 + * - r20: saved r1 (gp) + * - r21: saved ar.fpsr + * - r22: kernel's register backing store base (krbs_base) + * - r23: saved ar.bspstore + * - r24: saved ar.rnat + * - r25: saved ar.unat + * - r26: saved ar.pfs + * - r27: saved ar.rsc + * - r28: saved cr.iip + * - r29: saved cr.ipsr + * - r31: saved pr + * - b0: original contents (to be saved) + * On exit: + * - executing on bank 1 registers + * - psr.ic enabled, interrupts restored + * - p10: TRUE if syscall is invoked with more than 8 out + * registers or r15's Nat is true + * - r1: kernel's gp + * - r3: preserved (same as on entry) + * - r8: -EINVAL if p10 is true + * - r12: points to kernel stack + * - r13: points to current task + * - p15: TRUE if interrupts need to be re-enabled + * - ar.fpsr: set to kernel settings + */ +GLOBAL_ENTRY(ia64_syscall_setup) +#ifndef XEN +#if PT(B6) != 0 +# error This code assumes that b6 is the first field in pt_regs. +#endif +#endif + st8 [r1]=r19 // save b6 + add r16=PT(CR_IPSR),r1 // initialize first base pointer + add r17=PT(R11),r1 // initialize second base pointer + ;; + alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable + st8 [r16]=r29,PT(AR_PFS)-PT(CR_IPSR) // save cr.ipsr + tnat.nz p8,p0=in0 + + st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11 + tnat.nz p9,p0=in1 +(pKStk) mov r18=r0 // make sure r18 isn't NaT + ;; + + st8 [r16]=r26,PT(CR_IFS)-PT(AR_PFS) // save ar.pfs + st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip + mov r28=b0 // save b0 (2 cyc) + ;; + + st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat + dep r19=0,r19,38,26 // clear all bits but 0..37 [I0] +(p8) mov in0=-1 + ;; + + st8 [r16]=r19,PT(AR_RNAT)-PT(CR_IFS) // store ar.pfs.pfm in cr.ifs + extr.u r11=r19,7,7 // I0 // get sol of ar.pfs + and r8=0x7f,r19 // A // get sof of ar.pfs + + st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc + tbit.nz p15,p0=r29,IA64_PSR_I_BIT // I0 +(p9) mov in1=-1 + ;; + +(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 + tnat.nz p10,p0=in2 + add r11=8,r11 + ;; +(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field +(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field + tnat.nz p11,p0=in3 + ;; +(p10) mov in2=-1 + tnat.nz p12,p0=in4 // [I0] +(p11) mov in3=-1 + ;; +(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat +(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore + shl r18=r18,16 // compute ar.rsc to be used for "loadrs" + ;; + st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates + st8 [r17]=r28,PT(R1)-PT(B0) // save b0 + tnat.nz p13,p0=in5 // [I0] + ;; + st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs" + st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1 +(p12) mov in4=-1 + ;; + +.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12 +.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13 +(p13) mov in5=-1 + ;; + st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr + tnat.nz p14,p0=in6 + cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8 + ;; + stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) +(p9) tnat.nz p10,p0=r15 + adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) + + st8.spill [r17]=r15 // save r15 + tnat.nz p8,p0=in7 + nop.i 0 + + mov r13=r2 // establish `current' + movl r1=__gp // establish kernel global pointer + ;; +(p14) mov in6=-1 +(p8) mov in7=-1 + nop.i 0 + + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + movl r17=FPSR_DEFAULT + ;; + mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value +(p10) mov r8=-EINVAL + br.ret.sptk.many b7 +END(ia64_syscall_setup) + + .org ia64_ivt+0x3c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3c00 Entry 15 (size 64 bundles) Reserved + DBG_FAULT(15) + FAULT(15) + + /* + * Squatting in this space ... + * + * This special case dispatcher for illegal operation faults allows preserved + * registers to be modified through a callback function (asm only) that is handed + * back from the fault handler in r8. Up to three arguments can be passed to the + * callback function by returning an aggregate with the callback as its first + * element, followed by the arguments. + */ +ENTRY(dispatch_illegal_op_fault) + SAVE_MIN_WITH_COVER + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer for SAVE_REST + ;; + alloc r14=ar.pfs,0,0,1,0 // must be first in insn group + mov out0=ar.ec + ;; + SAVE_REST + ;; + br.call.sptk.many rp=ia64_illegal_op_fault +.ret0: ;; + alloc r14=ar.pfs,0,0,3,0 // must be first in insn group + mov out0=r9 + mov out1=r10 + mov out2=r11 + movl r15=ia64_leave_kernel + ;; + mov rp=r15 + mov b6=r8 + ;; + cmp.ne p6,p0=0,r8 +(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel + br.sptk.many ia64_leave_kernel +END(dispatch_illegal_op_fault) + + .org ia64_ivt+0x4000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4000 Entry 16 (size 64 bundles) Reserved + DBG_FAULT(16) + FAULT(16) + +#ifdef XEN + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + +ENTRY(dispatch_privop_fault) + SAVE_MIN_WITH_COVER + ;; + alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + mov out2=cr.isr // FIXME: pity to make this slow access twice + mov out3=cr.itir + + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.sptk.many ia64_prepare_handle_privop +END(dispatch_privop_fault) +#endif + + + .org ia64_ivt+0x4400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4400 Entry 17 (size 64 bundles) Reserved + DBG_FAULT(17) + FAULT(17) + +ENTRY(non_syscall) + SAVE_MIN_WITH_COVER + + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + + alloc r14=ar.pfs,0,0,2,0 + mov out0=cr.iim + add out1=16,sp + adds r3=8,r2 // set up second base pointer for SAVE_REST + + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + movl r15=ia64_leave_kernel + ;; + SAVE_REST + mov rp=r15 + ;; + br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr +END(non_syscall) + + .org ia64_ivt+0x4800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4800 Entry 18 (size 64 bundles) Reserved + DBG_FAULT(18) + FAULT(18) + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ + +ENTRY(dispatch_unaligned_handler) + SAVE_MIN_WITH_COVER + ;; + alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.sptk.many ia64_prepare_handle_unaligned +END(dispatch_unaligned_handler) + + .org ia64_ivt+0x4c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4c00 Entry 19 (size 64 bundles) Reserved + DBG_FAULT(19) + FAULT(19) + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ + +ENTRY(dispatch_to_fault_handler) + /* + * Input: + * psr.ic: off + * r19: fault vector number (e.g., 24 for General Exception) + * r31: contains saved predicates (pr) + */ + SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,5,0 + mov out0=r15 + mov out1=cr.isr + mov out2=cr.ifa + mov out3=cr.iim + mov out4=cr.itir + ;; + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer for SAVE_REST + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.call.sptk.many b6=ia64_fault +END(dispatch_to_fault_handler) + +// +// --- End of long entries, Beginning of short entries +// + + .org ia64_ivt+0x5000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) +ENTRY(page_not_present) +#ifdef XEN + REFLECT(20) +#endif + DBG_FAULT(20) + mov r16=cr.ifa + rsm psr.dt + /* + * The Linux page fault handler doesn't expect non-present pages to be in + * the TLB. Flush the existing entry now, so we meet that expectation. + */ + mov r17=PAGE_SHIFT<<2 + ;; + ptc.l r16,r17 + ;; + mov r31=pr + srlz.d + br.sptk.many page_fault +END(page_not_present) + + .org ia64_ivt+0x5100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) +ENTRY(key_permission) +#ifdef XEN + REFLECT(21) +#endif + DBG_FAULT(21) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.sptk.many page_fault +END(key_permission) + + .org ia64_ivt+0x5200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) +ENTRY(iaccess_rights) +#ifdef XEN + REFLECT(22) +#endif + DBG_FAULT(22) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.sptk.many page_fault +END(iaccess_rights) + + .org ia64_ivt+0x5300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) +ENTRY(daccess_rights) +#ifdef XEN + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=23 + movl r20=0x5300 + br.sptk.many fast_access_reflect;; +#endif + DBG_FAULT(23) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.sptk.many page_fault +END(daccess_rights) + + .org ia64_ivt+0x5400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) +ENTRY(general_exception) + DBG_FAULT(24) + mov r16=cr.isr + mov r31=pr + ;; +#ifdef XEN + cmp4.ge p6,p0=0x20,r16 +(p6) br.sptk.many dispatch_privop_fault +#else + cmp4.eq p6,p0=0,r16 +(p6) br.sptk.many dispatch_illegal_op_fault +#endif + ;; + mov r19=24 // fault number + br.sptk.many dispatch_to_fault_handler +END(general_exception) + + .org ia64_ivt+0x5500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) +ENTRY(disabled_fp_reg) +#ifdef XEN + REFLECT(25) +#endif + DBG_FAULT(25) + rsm psr.dfh // ensure we can access fph + ;; + srlz.d + mov r31=pr + mov r19=25 + br.sptk.many dispatch_to_fault_handler +END(disabled_fp_reg) + + .org ia64_ivt+0x5600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) +ENTRY(nat_consumption) +#ifdef XEN + REFLECT(26) +#endif + DBG_FAULT(26) + FAULT(26) +END(nat_consumption) + + .org ia64_ivt+0x5700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5700 Entry 27 (size 16 bundles) Speculation (40) +ENTRY(speculation_vector) +#ifdef XEN + // this probably need not reflect... + REFLECT(27) +#endif + DBG_FAULT(27) + /* + * A [f]chk.[as] instruction needs to take the branch to the recovery code but + * this part of the architecture is not implemented in hardware on some CPUs, such + * as Itanium. Thus, in general we need to emulate the behavior. IIM contains + * the relative target (not yet sign extended). So after sign extending it we + * simply add it to IIP. We also need to reset the EI field of the IPSR to zero, + * i.e., the slot to restart into. + * + * cr.imm contains zero_ext(imm21) + */ + mov r18=cr.iim + ;; + mov r17=cr.iip + shl r18=r18,43 // put sign bit in position (43=64-21) + ;; + + mov r16=cr.ipsr + shr r18=r18,39 // sign extend (39=43-4) + ;; + + add r17=r17,r18 // now add the offset + ;; + mov cr.iip=r17 + dep r16=0,r16,41,2 // clear EI + ;; + + mov cr.ipsr=r16 + ;; + + rfi // and go back +END(speculation_vector) + + .org ia64_ivt+0x5800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5800 Entry 28 (size 16 bundles) Reserved + DBG_FAULT(28) + FAULT(28) + + .org ia64_ivt+0x5900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) +ENTRY(debug_vector) +#ifdef XEN + REFLECT(29) +#endif + DBG_FAULT(29) + FAULT(29) +END(debug_vector) + + .org ia64_ivt+0x5a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) +ENTRY(unaligned_access) +#ifdef XEN + REFLECT(30) +#endif + DBG_FAULT(30) + mov r16=cr.ipsr + mov r31=pr // prepare to save predicates + ;; + br.sptk.many dispatch_unaligned_handler +END(unaligned_access) + + .org ia64_ivt+0x5b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) +ENTRY(unsupported_data_reference) +#ifdef XEN + REFLECT(31) +#endif + DBG_FAULT(31) + FAULT(31) +END(unsupported_data_reference) + + .org ia64_ivt+0x5c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) +ENTRY(floating_point_fault) +#ifdef XEN + REFLECT(32) +#endif + DBG_FAULT(32) + FAULT(32) +END(floating_point_fault) + + .org ia64_ivt+0x5d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) +ENTRY(floating_point_trap) +#ifdef XEN + REFLECT(33) +#endif + DBG_FAULT(33) + FAULT(33) +END(floating_point_trap) + + .org ia64_ivt+0x5e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) +ENTRY(lower_privilege_trap) +#ifdef XEN + REFLECT(34) +#endif + DBG_FAULT(34) + FAULT(34) +END(lower_privilege_trap) + + .org ia64_ivt+0x5f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) +ENTRY(taken_branch_trap) +#ifdef XEN + REFLECT(35) +#endif + DBG_FAULT(35) + FAULT(35) +END(taken_branch_trap) + + .org ia64_ivt+0x6000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) +ENTRY(single_step_trap) +#ifdef XEN + REFLECT(36) +#endif + DBG_FAULT(36) + FAULT(36) +END(single_step_trap) + + .org ia64_ivt+0x6100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6100 Entry 37 (size 16 bundles) Reserved + DBG_FAULT(37) + FAULT(37) + + .org ia64_ivt+0x6200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6200 Entry 38 (size 16 bundles) Reserved + DBG_FAULT(38) + FAULT(38) + + .org ia64_ivt+0x6300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6300 Entry 39 (size 16 bundles) Reserved + DBG_FAULT(39) + FAULT(39) + + .org ia64_ivt+0x6400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6400 Entry 40 (size 16 bundles) Reserved + DBG_FAULT(40) + FAULT(40) + + .org ia64_ivt+0x6500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6500 Entry 41 (size 16 bundles) Reserved + DBG_FAULT(41) + FAULT(41) + + .org ia64_ivt+0x6600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6600 Entry 42 (size 16 bundles) Reserved + DBG_FAULT(42) + FAULT(42) + + .org ia64_ivt+0x6700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6700 Entry 43 (size 16 bundles) Reserved + DBG_FAULT(43) + FAULT(43) + + .org ia64_ivt+0x6800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6800 Entry 44 (size 16 bundles) Reserved + DBG_FAULT(44) + FAULT(44) + + .org ia64_ivt+0x6900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) +ENTRY(ia32_exception) +#ifdef XEN + REFLECT(45) +#endif + DBG_FAULT(45) + FAULT(45) +END(ia32_exception) + + .org ia64_ivt+0x6a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) +ENTRY(ia32_intercept) +#ifdef XEN + REFLECT(46) +#endif + DBG_FAULT(46) +#ifdef CONFIG_IA32_SUPPORT + mov r31=pr + mov r16=cr.isr + ;; + extr.u r17=r16,16,8 // get ISR.code + mov r18=ar.eflag + mov r19=cr.iim // old eflag value + ;; + cmp.ne p6,p0=2,r17 +(p6) br.cond.spnt 1f // not a system flag fault + xor r16=r18,r19 + ;; + extr.u r17=r16,18,1 // get the eflags.ac bit + ;; + cmp.eq p6,p0=0,r17 +(p6) br.cond.spnt 1f // eflags.ac bit didn't change + ;; + mov pr=r31,-1 // restore predicate registers + rfi + +1: +#endif // CONFIG_IA32_SUPPORT + FAULT(46) +END(ia32_intercept) + + .org ia64_ivt+0x6b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) +ENTRY(ia32_interrupt) +#ifdef XEN + REFLECT(47) +#endif + DBG_FAULT(47) +#ifdef CONFIG_IA32_SUPPORT + mov r31=pr + br.sptk.many dispatch_to_ia32_handler +#else + FAULT(47) +#endif +END(ia32_interrupt) + + .org ia64_ivt+0x6c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6c00 Entry 48 (size 16 bundles) Reserved + DBG_FAULT(48) + FAULT(48) + + .org ia64_ivt+0x6d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6d00 Entry 49 (size 16 bundles) Reserved + DBG_FAULT(49) + FAULT(49) + + .org ia64_ivt+0x6e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6e00 Entry 50 (size 16 bundles) Reserved + DBG_FAULT(50) + FAULT(50) + + .org ia64_ivt+0x6f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6f00 Entry 51 (size 16 bundles) Reserved + DBG_FAULT(51) + FAULT(51) + + .org ia64_ivt+0x7000 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7000 Entry 52 (size 16 bundles) Reserved + DBG_FAULT(52) + FAULT(52) + + .org ia64_ivt+0x7100 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7100 Entry 53 (size 16 bundles) Reserved + DBG_FAULT(53) + FAULT(53) + + .org ia64_ivt+0x7200 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7200 Entry 54 (size 16 bundles) Reserved + DBG_FAULT(54) + FAULT(54) + + .org ia64_ivt+0x7300 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7300 Entry 55 (size 16 bundles) Reserved + DBG_FAULT(55) + FAULT(55) + + .org ia64_ivt+0x7400 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7400 Entry 56 (size 16 bundles) Reserved + DBG_FAULT(56) + FAULT(56) + + .org ia64_ivt+0x7500 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7500 Entry 57 (size 16 bundles) Reserved + DBG_FAULT(57) + FAULT(57) + + .org ia64_ivt+0x7600 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7600 Entry 58 (size 16 bundles) Reserved + DBG_FAULT(58) + FAULT(58) + + .org ia64_ivt+0x7700 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7700 Entry 59 (size 16 bundles) Reserved + DBG_FAULT(59) + FAULT(59) + + .org ia64_ivt+0x7800 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7800 Entry 60 (size 16 bundles) Reserved + DBG_FAULT(60) + FAULT(60) + + .org ia64_ivt+0x7900 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7900 Entry 61 (size 16 bundles) Reserved + DBG_FAULT(61) + FAULT(61) + + .org ia64_ivt+0x7a00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7a00 Entry 62 (size 16 bundles) Reserved + DBG_FAULT(62) + FAULT(62) + + .org ia64_ivt+0x7b00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7b00 Entry 63 (size 16 bundles) Reserved + DBG_FAULT(63) + FAULT(63) + + .org ia64_ivt+0x7c00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7c00 Entry 64 (size 16 bundles) Reserved + DBG_FAULT(64) + FAULT(64) + + .org ia64_ivt+0x7d00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7d00 Entry 65 (size 16 bundles) Reserved + DBG_FAULT(65) + FAULT(65) + + .org ia64_ivt+0x7e00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7e00 Entry 66 (size 16 bundles) Reserved + DBG_FAULT(66) + FAULT(66) + + .org ia64_ivt+0x7f00 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7f00 Entry 67 (size 16 bundles) Reserved + DBG_FAULT(67) + FAULT(67) + +#ifdef XEN + .org ia64_ivt+0x8000 +GLOBAL_ENTRY(dispatch_reflection) + /* + * Input: + * psr.ic: off + * r19: intr type (offset into ivt, see ia64_int.h) + * r31: contains saved predicates (pr) + */ + SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,5,0 + mov out4=r15 + mov out0=cr.ifa + adds out1=16,sp + mov out2=cr.isr + mov out3=cr.iim +// mov out3=cr.itir + + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.sptk.many ia64_prepare_handle_reflection +END(dispatch_reflection) + +#define SAVE_MIN_COVER_DONE DO_SAVE_MIN(,mov r30=cr.ifs,) + +// same as dispatch_break_fault except cover has already been done +GLOBAL_ENTRY(dispatch_slow_hyperprivop) + SAVE_MIN_COVER_DONE + ;; + br.sptk.many dispatch_break_fault_post_save +END(dispatch_slow_hyperprivop) +#endif + +#ifdef CONFIG_IA32_SUPPORT + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ + + // IA32 interrupt entry point + +ENTRY(dispatch_to_ia32_handler) + SAVE_MIN + ;; + mov r14=cr.isr + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i + adds r3=8,r2 // Base pointer for SAVE_REST + ;; + SAVE_REST + ;; + mov r15=0x80 + shr r14=r14,16 // Get interrupt number + ;; + cmp.ne p6,p0=r14,r15 +(p6) br.call.dpnt.many b6=non_ia32_syscall + + adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions + adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp + ;; + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + ld8 r8=[r14] // get r8 + ;; + st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) + ;; + alloc r15=ar.pfs,0,0,6,0 // must first in an insn group + ;; + ld4 r8=[r14],8 // r8 == eax (syscall number) + mov r15=IA32_NR_syscalls + ;; + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx + ;; + ld4 out2=[r14],8 // r10 == edx + ;; + ld4 out0=[r14] // r11 == ebx + adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp + ;; + ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp + ;; + ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi + adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 out4=[r14] // r15 == edi + movl r16=ia32_syscall_table + ;; +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ld4 r2=[r2] // r2 = current_thread_info()->flags + ;; + ld8 r16=[r16] + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit + ;; + mov b6=r16 + movl r15=ia32_ret_from_syscall + cmp.eq p8,p0=r2,r0 + ;; + mov rp=r15 +(p8) br.call.sptk.many b6=b6 + br.cond.sptk ia32_trace_syscall + +non_ia32_syscall: + alloc r15=ar.pfs,0,0,2,0 + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs + ;; // avoid WAW on CFM + br.call.sptk.many rp=ia32_bad_interrupt +.ret1: movl r15=ia64_leave_kernel + ;; + mov rp=r15 + br.ret.sptk.many rp +END(dispatch_to_ia32_handler) + +#endif /* CONFIG_IA32_SUPPORT */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/mm_init.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/mm_init.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,549 @@ +/* + * Initialize MMU support. + * + * Copyright (C) 1998-2003 Hewlett-Packard Co + * David Mosberger-Tang <davidm@xxxxxxxxxx> + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#ifdef XEN +#include <xen/sched.h> +#endif +#include <linux/bootmem.h> +#include <linux/efi.h> +#include <linux/elf.h> +#include <linux/mm.h> +#include <linux/mmzone.h> +#include <linux/module.h> +#ifndef XEN +#include <linux/personality.h> +#endif +#include <linux/reboot.h> +#include <linux/slab.h> +#include <linux/swap.h> +#ifndef XEN +#include <linux/proc_fs.h> +#endif + +#ifndef XEN +#include <asm/a.out.h> +#endif +#include <asm/bitops.h> +#include <asm/dma.h> +#ifndef XEN +#include <asm/ia32.h> +#endif +#include <asm/io.h> +#include <asm/machvec.h> +#include <asm/numa.h> +#include <asm/patch.h> +#include <asm/pgalloc.h> +#include <asm/sal.h> +#include <asm/sections.h> +#include <asm/system.h> +#include <asm/tlb.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/mca.h> + +#ifndef XEN +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +#endif + +extern void ia64_tlb_init (void); + +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; + +#ifdef CONFIG_VIRTUAL_MEM_MAP +unsigned long vmalloc_end = VMALLOC_END_INIT; +EXPORT_SYMBOL(vmalloc_end); +struct page *vmem_map; +EXPORT_SYMBOL(vmem_map); +#endif + +static int pgt_cache_water[2] = { 25, 50 }; + +struct page *zero_page_memmap_ptr; /* map entry for zero page */ +EXPORT_SYMBOL(zero_page_memmap_ptr); + +#ifdef XEN +void *high_memory; +EXPORT_SYMBOL(high_memory); + +///////////////////////////////////////////// +// following from linux-2.6.7/mm/mmap.c +/* description of effects of mapping type and prot in current implementation. + * this is due to the limited x86 page protection hardware. The expected + * behavior is in parens: + * + * map_type prot + * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC + * MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes + * w: (no) no w: (no) no w: (yes) yes w: (no) no + * x: (no) no x: (no) yes x: (no) yes x: (yes) yes + * + * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes + * w: (no) no w: (no) no w: (copy) copy w: (no) no + * x: (no) no x: (no) yes x: (no) yes x: (yes) yes + * + */ +pgprot_t protection_map[16] = { + __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, + __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 +}; + +void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) +{ + printf("insert_vm_struct: called, not implemented yet\n"); +} + +///////////////////////////////////////////// +//following from linux/mm/memory.c + +#ifndef __ARCH_HAS_4LEVEL_HACK +/* + * Allocate page upper directory. + * + * We've already handled the fast-path in-line, and we own the + * page table lock. + * + * On a two-level or three-level page table, this ends up actually being + * entirely optimized away. + */ +pud_t fastcall *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) +{ + pud_t *new; + + spin_unlock(&mm->page_table_lock); + new = pud_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pgd_present(*pgd)) { + pud_free(new); + goto out; + } + pgd_populate(mm, pgd, new); + out: + return pud_offset(pgd, address); +} + +/* + * Allocate page middle directory. + * + * We've already handled the fast-path in-line, and we own the + * page table lock. + * + * On a two-level page table, this ends up actually being entirely + * optimized away. + */ +pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) +{ + pmd_t *new; + + spin_unlock(&mm->page_table_lock); + new = pmd_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pud_present(*pud)) { + pmd_free(new); + goto out; + } + pud_populate(mm, pud, new); + out: + return pmd_offset(pud, address); +} +#endif + +pte_t fastcall * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +{ + if (!pmd_present(*pmd)) { + struct page *new; + + spin_unlock(&mm->page_table_lock); + new = pte_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pmd_present(*pmd)) { + pte_free(new); + goto out; + } + inc_page_state(nr_page_table_pages); + pmd_populate(mm, pmd, new); + } +out: + return pte_offset_map(pmd, address); +} +///////////////////////////////////////////// +#endif /* XEN */ + +#if 0 +void +update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) +{ + unsigned long addr; + struct page *page; + + if (!pte_exec(pte)) + return; /* not an executable page... */ + + page = pte_page(pte); + /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ + addr = (unsigned long) page_address(page); + + if (test_bit(PG_arch_1, &page->flags)) + return; /* i-cache is already coherent with d-cache */ + + flush_icache_range(addr, addr + PAGE_SIZE); + set_bit(PG_arch_1, &page->flags); /* mark page as clean */ +} +#endif + +inline void +ia64_set_rbs_bot (void) +{ +#ifdef XEN + unsigned stack_size = MAX_USER_STACK_SIZE; +#else + unsigned long stack_size = current->rlim[RLIMIT_STACK].rlim_max & -16; +#endif + + if (stack_size > MAX_USER_STACK_SIZE) + stack_size = MAX_USER_STACK_SIZE; + current->arch._thread.rbs_bot = STACK_TOP - stack_size; +} + +/* + * This performs some platform-dependent address space initialization. + * On IA-64, we want to setup the VM area for the register backing + * store (which grows upwards) and install the gateway page which is + * used for signal trampolines, etc. + */ +void +ia64_init_addr_space (void) +{ +#ifdef XEN +printf("ia64_init_addr_space: called, not implemented\n"); +#else + struct vm_area_struct *vma; + + ia64_set_rbs_bot(); + + /* + * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore + * the problem. When the process attempts to write to the register backing store + * for the first time, it will get a SEGFAULT in this case. + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_start = current->arch._thread.rbs_bot & PAGE_MASK; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; + vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; + insert_vm_struct(current->mm, vma); + } + + /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ + if (!(current->personality & MMAP_PAGE_ZERO)) { + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_end = PAGE_SIZE; + vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); + vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; + insert_vm_struct(current->mm, vma); + } + } +#endif +} + +setup_gate (void) +{ + printk("setup_gate not-implemented.\n"); +} + +void __devinit +ia64_mmu_init (void *my_cpu_data) +{ + unsigned long psr, pta, impl_va_bits; + extern void __devinit tlb_init (void); + int cpu; + +#ifdef CONFIG_DISABLE_VHPT +# define VHPT_ENABLE_BIT 0 +#else +# define VHPT_ENABLE_BIT 1 +#endif + + /* Pin mapping for percpu area into TLB */ + psr = ia64_clear_ic(); + ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, + pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), + PERCPU_PAGE_SHIFT); + + ia64_set_psr(psr); + ia64_srlz_i(); + + /* + * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped + * address space. The IA-64 architecture guarantees that at least 50 bits of + * virtual address space are implemented but if we pick a large enough page size + * (e.g., 64KB), the mapped address space is big enough that it will overlap with + * VMLPT. I assume that once we run on machines big enough to warrant 64KB pages, + * IMPL_VA_MSB will be significantly bigger, so this is unlikely to become a + * problem in practice. Alternatively, we could truncate the top of the mapped + * address space to not permit mappings that would overlap with the VMLPT. + * --davidm 00/12/06 + */ +# define pte_bits 3 +# define mapped_space_bits (3*(PAGE_SHIFT - pte_bits) + PAGE_SHIFT) + /* + * The virtual page table has to cover the entire implemented address space within + * a region even though not all of this space may be mappable. The reason for + * this is that the Access bit and Dirty bit fault handlers perform + * non-speculative accesses to the virtual page table, so the address range of the + * virtual page table itself needs to be covered by virtual page table. + */ +# define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) +# define POW2(n) (1ULL << (n)) + + impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); + + if (impl_va_bits < 51 || impl_va_bits > 61) + panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); + +#ifdef XEN + vhpt_init(); +#endif +#if 0 + /* place the VMLPT at the end of each page-table mapped region: */ + pta = POW2(61) - POW2(vmlpt_bits); + + if (POW2(mapped_space_bits) >= pta) + panic("mm/init: overlap between virtually mapped linear page table and " + "mapped kernel space!"); + /* + * Set the (virtually mapped linear) page table address. Bit + * 8 selects between the short and long format, bits 2-7 the + * size of the table, and bit 0 whether the VHPT walker is + * enabled. + */ + ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); +#endif + ia64_tlb_init(); + +#ifdef CONFIG_HUGETLB_PAGE + ia64_set_rr(HPAGE_REGION_BASE, HPAGE_SHIFT << 2); + ia64_srlz_d(); +#endif + + cpu = smp_processor_id(); + +#ifndef XEN + /* mca handler uses cr.lid as key to pick the right entry */ + ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID); + + /* insert this percpu data information into our list for MCA recovery purposes */ + ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); + /* Also save per-cpu tlb flush recipe for use in physical mode mca handler */ + ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base; + ia64_mca_tlb_list[cpu].ptce_count[0] = local_cpu_data->ptce_count[0]; + ia64_mca_tlb_list[cpu].ptce_count[1] = local_cpu_data->ptce_count[1]; + ia64_mca_tlb_list[cpu].ptce_stride[0] = local_cpu_data->ptce_stride[0]; + ia64_mca_tlb_list[cpu].ptce_stride[1] = local_cpu_data->ptce_stride[1]; +#endif +} + +#ifdef CONFIG_VIRTUAL_MEM_MAP + +int +create_mem_map_page_table (u64 start, u64 end, void *arg) +{ + unsigned long address, start_page, end_page; + struct page *map_start, *map_end; + int node; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); + map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); + + start_page = (unsigned long) map_start & PAGE_MASK; + end_page = PAGE_ALIGN((unsigned long) map_end); + node = paddr_to_nid(__pa(start)); + + for (address = start_page; address < end_page; address += PAGE_SIZE) { + pgd = pgd_offset_k(address); + if (pgd_none(*pgd)) + pgd_populate(&init_mm, pgd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); + pmd = pmd_offset(pgd, address); + + if (pmd_none(*pmd)) + pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); + pte = pte_offset_kernel(pmd, address); + + if (pte_none(*pte)) + set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)) >> PAGE_SHIFT, + PAGE_KERNEL)); + } + return 0; +} + +struct memmap_init_callback_data { + struct page *start; + struct page *end; + int nid; + unsigned long zone; +}; + +static int +virtual_memmap_init (u64 start, u64 end, void *arg) +{ + struct memmap_init_callback_data *args; + struct page *map_start, *map_end; + + args = (struct memmap_init_callback_data *) arg; + + map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); + map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); + + if (map_start < args->start) + map_start = args->start; + if (map_end > args->end) + map_end = args->end; + + /* + * We have to initialize "out of bounds" struct page elements that fit completely + * on the same pages that were allocated for the "in bounds" elements because they + * may be referenced later (and found to be "reserved"). + */ + map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page); + map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end) + / sizeof(struct page)); + + if (map_start < map_end) + memmap_init_zone(map_start, (unsigned long) (map_end - map_start), + args->nid, args->zone, page_to_pfn(map_start)); + return 0; +} + +void +memmap_init (struct page *start, unsigned long size, int nid, + unsigned long zone, unsigned long start_pfn) +{ + if (!vmem_map) + memmap_init_zone(start, size, nid, zone, start_pfn); + else { + struct memmap_init_callback_data args; + + args.start = start; + args.end = start + size; + args.nid = nid; + args.zone = zone; + + efi_memmap_walk(virtual_memmap_init, &args); + } +} + +int +ia64_pfn_valid (unsigned long pfn) +{ + char byte; + struct page *pg = pfn_to_page(pfn); + + return (__get_user(byte, (char *) pg) == 0) + && ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK)) + || (__get_user(byte, (char *) (pg + 1) - 1) == 0)); +} +EXPORT_SYMBOL(ia64_pfn_valid); + +int +find_largest_hole (u64 start, u64 end, void *arg) +{ + u64 *max_gap = arg; + + static u64 last_end = PAGE_OFFSET; + + /* NOTE: this algorithm assumes efi memmap table is ordered */ + +#ifdef XEN +//printf("find_largest_hole: start=%lx,end=%lx,max_gap=%lx\n",start,end,*(unsigned long *)arg); +#endif + if (*max_gap < (start - last_end)) + *max_gap = start - last_end; + last_end = end; +#ifdef XEN +//printf("find_largest_hole2: max_gap=%lx,last_end=%lx\n",*max_gap,last_end); +#endif + return 0; +} +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + +static int +count_reserved_pages (u64 start, u64 end, void *arg) +{ + unsigned long num_reserved = 0; + unsigned long *count = arg; + + for (; start < end; start += PAGE_SIZE) + if (PageReserved(virt_to_page(start))) + ++num_reserved; + *count += num_reserved; + return 0; +} + +/* + * Boot command-line option "nolwsys" can be used to disable the use of any light-weight + * system call handler. When this option is in effect, all fsyscalls will end up bubbling + * down into the kernel and calling the normal (heavy-weight) syscall handler. This is + * useful for performance testing, but conceivably could also come in handy for debugging + * purposes. + */ + +static int nolwsys; + +static int __init +nolwsys_setup (char *s) +{ + nolwsys = 1; + return 1; +} + +__setup("nolwsys", nolwsys_setup); + +void +mem_init (void) +{ +#ifdef CONFIG_PCI + /* + * This needs to be called _after_ the command line has been parsed but _before_ + * any drivers that may need the PCI DMA interface are initialized or bootmem has + * been freed. + */ + platform_dma_init(); +#endif + +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/pcdp.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/pcdp.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,120 @@ +/* + * Parse the EFI PCDP table to locate the console device. + * + * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P. + * Khalid Aziz <khalid.aziz@xxxxxx> + * Alex Williamson <alex.williamson@xxxxxx> + * Bjorn Helgaas <bjorn.helgaas@xxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/acpi.h> +#include <linux/console.h> +#include <linux/efi.h> +#include <linux/serial.h> +#ifdef XEN +#include <linux/errno.h> +#endif +#include "pcdp.h" + +static int __init +setup_serial_console(struct pcdp_uart *uart) +{ +#ifdef XEN + extern struct ns16550_defaults ns16550_com1; + ns16550_com1.baud = uart->baud; + ns16550_com1.io_base = uart->addr.address; + if (uart->bits) + ns16550_com1.data_bits = uart->bits; + return 0; +#else +#ifdef CONFIG_SERIAL_8250_CONSOLE + int mmio; + static char options[64]; + + mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); + snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d", + mmio ? "mmio" : "io", uart->addr.address, uart->baud, + uart->bits ? uart->bits : 8); + + return early_serial_console_init(options); +#else + return -ENODEV; +#endif +#endif +} + +#ifndef XEN +static int __init +setup_vga_console(struct pcdp_vga *vga) +{ +#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) + if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) { + printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n"); + return -ENODEV; + } + + conswitchp = &vga_con; + printk(KERN_INFO "PCDP: VGA console\n"); + return 0; +#else + return -ENODEV; +#endif +} +#endif + +int __init +efi_setup_pcdp_console(char *cmdline) +{ + struct pcdp *pcdp; + struct pcdp_uart *uart; + struct pcdp_device *dev, *end; + int i, serial = 0; + + pcdp = efi.hcdp; + if (!pcdp) + return -ENODEV; + +#ifndef XEN + printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp)); +#endif + + if (strstr(cmdline, "console=hcdp")) { + if (pcdp->rev < 3) + serial = 1; + } else if (strstr(cmdline, "console=")) { +#ifndef XEN + printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n"); +#endif + return -ENODEV; + } + + if (pcdp->rev < 3 && efi_uart_console_only()) + serial = 1; + + for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { + if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { + if (uart->type == PCDP_CONSOLE_UART) { + return setup_serial_console(uart); + } + } + } + +#ifndef XEN + end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); + for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts); + dev < end; + dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { + if (dev->flags & PCDP_PRIMARY_CONSOLE) { + if (dev->type == PCDP_CONSOLE_VGA) { + return setup_vga_console((struct pcdp_vga *) dev); + } + } + } +#endif + + return -ENODEV; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/privop.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/privop.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1130 @@ +/* + * Privileged operation "API" handling functions. + * + * Copyright (C) 2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <asm/privop.h> +#include <asm/vcpu.h> +#include <asm/processor.h> +#include <asm/delay.h> // Debug only +//#include <debug.h> + +long priv_verbose=0; + +/************************************************************************** +Hypercall bundle creation +**************************************************************************/ + + +void build_hypercall_bundle(UINT64 *imva, UINT64 brkimm, UINT64 hypnum, UINT64 ret) +{ + INST64_A5 slot0; + INST64_I19 slot1; + INST64_B4 slot2; + IA64_BUNDLE bundle; + + // slot1: mov r2 = hypnum (low 20 bits) + slot0.inst = 0; + slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9; + slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7; + slot0.imm5c = hypnum >> 16; slot0.s = 0; + // slot1: break brkimm + slot1.inst = 0; + slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0; + slot1.imm20 = brkimm; slot1.i = brkimm >> 20; + // if ret slot2: br.ret.sptk.many rp + // else slot2: br.cond.sptk.many rp + slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0; + slot2.wh = 0; slot2.d = 0; slot2.major = 0x0; + if (ret) { + slot2.btype = 4; slot2.x6 = 0x21; + } + else { + slot2.btype = 0; slot2.x6 = 0x20; + } + + bundle.i64[0] = 0; bundle.i64[1] = 0; + bundle.template = 0x11; + bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst; + bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18; + + *imva++ = bundle.i64[0]; *imva = bundle.i64[1]; +} + +/************************************************************************** +Privileged operation emulation routines +**************************************************************************/ + +IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst) +{ + return vcpu_rfi(vcpu); +} + +IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst) +{ + return vcpu_bsw0(vcpu); +} + +IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst) +{ + return vcpu_bsw1(vcpu); +} + +IA64FAULT priv_cover(VCPU *vcpu, INST64 inst) +{ + return vcpu_cover(vcpu); +} + +IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst) +{ + UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); + UINT64 addr_range; + + addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_l(vcpu,vadr,addr_range); +} + +IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst) +{ + UINT src = inst.M28.r3; + + // NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64) + if (src > 63) return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64))); + return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src)); +} + +IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst) +{ + UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); + UINT64 addr_range; + + addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_g(vcpu,vadr,addr_range); +} + +IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst) +{ + UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); + UINT64 addr_range; + + addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_ga(vcpu,vadr,addr_range); +} + +IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst) +{ + UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); + UINT64 addr_range; + + addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptr_d(vcpu,vadr,addr_range); +} + +IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst) +{ + UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); + UINT64 addr_range; + + addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptr_i(vcpu,vadr,addr_range); +} + +IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst) +{ + UINT64 padr; + UINT fault; + UINT src = inst.M46.r3; + + // NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64) + if (src > 63) + 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); + else return fault; +} + +IA64FAULT priv_tak(VCPU *vcpu, INST64 inst) +{ + UINT64 key; + UINT fault; + UINT src = inst.M46.r3; + + // NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64) + if (src > 63) + 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); + else return fault; +} + +/************************************ + * Insert translation register/cache +************************************/ + +IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst) +{ + UINT64 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); + + return (vcpu_itr_d(vcpu,slot,pte,itir,ifa)); +} + +IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst) +{ + UINT64 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); + + return (vcpu_itr_i(vcpu,slot,pte,itir,ifa)); +} + +IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst) +{ + UINT64 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); + + return (vcpu_itc_d(vcpu,pte,itir,ifa)); +} + +IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst) +{ + UINT64 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); + + return (vcpu_itc_i(vcpu,pte,itir,ifa)); +} + +/************************************* + * Moves to semi-privileged registers +*************************************/ + +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)); +} + +IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst) +{ + // I26 and M29 are identical for these fields + UINT64 ar3 = inst.M29.ar3; + + if (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); + else return IA64_ILLOP_FAULT; + } + else { + UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2); + return (vcpu_set_ar(vcpu,ar3,r2)); + } +} + +/******************************** + * Moves to privileged registers +********************************/ + +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)); +} + +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)); +} + +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)); +} + +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)); +} + +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)); +} + +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)); +} + +unsigned long to_cr_cnt[128] = { 0 }; + +IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst) +{ + UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2); + to_cr_cnt[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; + } +} + +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); +} + +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); +} + +/** + * @todo Check for reserved bits and return IA64_RSVDREG_FAULT. + */ +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); +} + +/********************************** + * Moves from privileged registers + **********************************/ + +IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + + if (inst.M43.r1 > 63) { // privified mov from cpuid + fault = vcpu_get_cpuid(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1-64, val); + } + else { + fault = vcpu_get_rr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1, val); + } + return fault; +} + +IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + + 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); + else return fault; +} + +IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + + 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); + else return fault; +} + +IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + + 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); + else return fault; +} + +IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) +{ + UINT64 val; + IA64FAULT fault; + + if (inst.M43.r1 > 63) { // privified mov from pmd + fault = vcpu_get_pmd(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1-64, val); + } + else { + fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1, val); + } + return fault; +} + +unsigned long from_cr_cnt[128] = { 0 }; + +#define cr_get(cr) \ + ((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \ + vcpu_set_gr(vcpu, tgt, val) : fault; + +IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst) +{ + UINT64 tgt = inst.M33.r1; + UINT64 val; + IA64FAULT fault; + + from_cr_cnt[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); + 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; +} + +IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst) +{ + UINT64 tgt = inst.M33.r1; + UINT64 val; + IA64FAULT fault; + + if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, tgt, val); + else return fault; +} + +/************************************************************************** +Privileged operation decode and dispatch routines +**************************************************************************/ + +IA64_SLOT_TYPE slot_types[0x20][3] = { + {M, I, I}, {M, I, I}, {M, I, I}, {M, I, I}, + {M, I, ILLEGAL}, {M, I, ILLEGAL}, + {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, + {M, M, I}, {M, M, I}, {M, M, I}, {M, M, I}, + {M, F, I}, {M, F, I}, + {M, M, F}, {M, M, F}, + {M, I, B}, {M, I, B}, + {M, B, B}, {M, B, B}, + {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, + {B, B, B}, {B, B, B}, + {M, M, B}, {M, M, B}, + {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, + {M, F, B}, {M, F, B}, + {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL} +}; + +// pointer to privileged emulation function +typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst); + +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 +}; + +struct { + unsigned long mov_to_ar_imm; + unsigned long mov_to_ar_reg; + unsigned long mov_from_ar; + unsigned long ssm; + unsigned long rsm; + unsigned long rfi; + unsigned long bsw0; + unsigned long bsw1; + unsigned long cover; + unsigned long fc; + unsigned long cpuid; + unsigned long Mpriv_cnt[64]; +} privcnt = { 0 }; + +unsigned long privop_trace = 0; + +IA64FAULT +priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) +{ + IA64_BUNDLE bundle; + IA64_BUNDLE __get_domain_bundle(UINT64); + int slot; + IA64_SLOT_TYPE slot_type; + INST64 inst; + PPEFCN pfunc; + unsigned long ipsr = regs->cr_ipsr; + UINT64 iip = regs->cr_iip; + int x6; + + // make a local copy of the bundle containing the privop +#if 1 + bundle = __get_domain_bundle(iip); + if (!bundle.i64[0] && !bundle.i64[1]) +#else + if (__copy_from_user(&bundle,iip,sizeof(bundle))) +#endif + { +//printf("*** priv_handle_op: privop bundle @%p not mapped, retrying\n",iip); + return vcpu_force_data_miss(vcpu,regs->cr_iip); + } +#if 0 + if (iip==0xa000000100001820) { + static int firstpagefault = 1; + if (firstpagefault) { + printf("*** First time to domain page fault!\n"); firstpagefault=0; + } + } +#endif + if (privop_trace) { + static long i = 400; + //if (i > 0) printf("privop @%p\n",iip); + if (i > 0) printf("priv_handle_op: @%p, 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; + 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); + + 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); + } + 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); + switch (slot_type) { + 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); + } +#endif + if (inst.M29.x3 != 0) break; + if (inst.M30.x4 == 8 && inst.M30.x2 == 2) { + privcnt.mov_to_ar_imm++; + return priv_mov_to_ar_imm(vcpu,inst); + } + if (inst.M44.x4 == 6) { + privcnt.ssm++; + return priv_ssm(vcpu,inst); + } + if (inst.M44.x4 == 7) { + privcnt.rsm++; + return priv_rsm(vcpu,inst); + } + break; + } + else if (inst.generic.major != 1) break; + x6 = inst.M29.x6; + if (x6 == 0x2a) { + if (inst.M29.r2 > 63 && inst.M29.ar3 < 8) + privcnt.mov_from_ar++; // privified mov from kr + else privcnt.mov_to_ar_reg++; + 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.M46.r3 > 63) { + if (x6 == 0x1e) x6 = 0x1b; + else x6 = 0x1a; + } + } + if (x6 == 52 && inst.M28.r3 > 63) + privcnt.fc++; + else if (x6 == 16 && inst.M43.r3 > 63) + privcnt.cpuid++; + else privcnt.Mpriv_cnt[x6]++; + return (*pfunc)(vcpu,inst); + break; + case B: + if (inst.generic.major != 0) break; + if (inst.B8.x6 == 0x08) { + IA64FAULT fault; + privcnt.rfi++; + fault = priv_rfi(vcpu,inst); + if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS; + return fault; + } + if (inst.B8.x6 == 0x0c) { + privcnt.bsw0++; + return priv_bsw0(vcpu,inst); + } + if (inst.B8.x6 == 0x0d) { + privcnt.bsw1++; + return priv_bsw1(vcpu,inst); + } + if (inst.B8.x6 == 0x0) { // break instr for privified cover + privcnt.cover++; + return priv_cover(vcpu,inst); + } + break; + case I: + if (inst.generic.major != 0) break; +#if 0 + if (inst.I26.x6 == 0 && inst.I26.x3 == 0) { + privcnt.cover++; + return priv_cover(vcpu,inst); + } +#endif + if (inst.I26.x3 != 0) break; // I26.x3 == I27.x3 + if (inst.I26.x6 == 0x2a) { + if (inst.I26.r2 > 63 && inst.I26.ar3 < 8) + privcnt.mov_from_ar++; // privified mov from kr + else privcnt.mov_to_ar_reg++; + return priv_mov_to_ar_reg(vcpu,inst); + } + if (inst.I27.x6 == 0x0a) { + privcnt.mov_to_ar_imm++; + return priv_mov_to_ar_imm(vcpu,inst); + } + break; + default: + break; + } + //printf("We who are about do die salute you\n"); + printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d), ipsr=%p\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); +} + +/** Emulate a privileged operation. + * + * This should probably return 0 on success and the "trap number" + * (e.g. illegal operation for bad register, priv op for an + * instruction that isn't allowed, etc.) on "failure" + * + * @param vcpu virtual cpu + * @param isrcode interrupt service routine code + * @return fault + */ +IA64FAULT +priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) +{ + IA64FAULT fault; + UINT64 ipsr = regs->cr_ipsr; + UINT64 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: returning ILLOP, not implemented!\n"); + while (1); + return IA64_ILLOP_FAULT; + } + //if (isrcode != 1 && isrcode != 2) return 0; + vcpu_set_regs(vcpu,regs); + privlvl = (ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT; + // 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!! + // 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=%p\n",isr); + return fault; +} + + +// FIXME: Move these to include/public/arch-ia64? +#define HYPERPRIVOP_RFI 0x1 +#define HYPERPRIVOP_RSM_DT 0x2 +#define HYPERPRIVOP_SSM_DT 0x3 +#define HYPERPRIVOP_COVER 0x4 +#define HYPERPRIVOP_ITC_D 0x5 +#define HYPERPRIVOP_ITC_I 0x6 +#define HYPERPRIVOP_SSM_I 0x7 +#define HYPERPRIVOP_GET_IVR 0x8 +#define HYPERPRIVOP_GET_TPR 0x9 +#define HYPERPRIVOP_SET_TPR 0xa +#define HYPERPRIVOP_EOI 0xb +#define HYPERPRIVOP_SET_ITM 0xc +#define HYPERPRIVOP_THASH 0xd +#define HYPERPRIVOP_PTC_GA 0xe +#define HYPERPRIVOP_ITR_D 0xf +#define HYPERPRIVOP_GET_RR 0x10 +#define HYPERPRIVOP_SET_RR 0x11 +#define HYPERPRIVOP_MAX 0x11 + +char *hyperpriv_str[HYPERPRIVOP_MAX+1] = { + 0, "rfi", "rsm.dt", "ssm.dt", "cover", "itc.d", "itc.i", "ssm.i", + "=ivr", "=tpr", "tpr=", "eoi", "itm=", "thash", "ptc.ga", "itr.d", + "=rr", "rr=", + 0 +}; + +unsigned long slow_hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; +unsigned long fast_hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; + +/* 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) +{ + struct vcpu *v = (struct domain *) current; + INST64 inst; + UINT64 val; + UINT64 itir, ifa; + +// FIXME: Handle faults appropriately for these + if (!iim || iim > HYPERPRIVOP_MAX) { + printf("bad hyperprivop; ignored\n"); + printf("iim=%d, iip=%p\n",iim,regs->cr_iip); + return 1; + } + slow_hyperpriv_cnt[iim]++; + switch(iim) { + case HYPERPRIVOP_RFI: + (void)vcpu_rfi(v); + return 0; // don't update iip + case HYPERPRIVOP_RSM_DT: + (void)vcpu_reset_psr_dt(v); + return 1; + case HYPERPRIVOP_SSM_DT: + (void)vcpu_set_psr_dt(v); + return 1; + case HYPERPRIVOP_COVER: + (void)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); + 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); + return 1; + case HYPERPRIVOP_SSM_I: + (void)vcpu_set_psr_i(v); + return 1; + case HYPERPRIVOP_GET_IVR: + (void)vcpu_get_ivr(v,&val); + regs->r8 = val; + return 1; + case HYPERPRIVOP_GET_TPR: + (void)vcpu_get_tpr(v,&val); + regs->r8 = val; + return 1; + case HYPERPRIVOP_SET_TPR: + (void)vcpu_set_tpr(v,regs->r8); + return 1; + case HYPERPRIVOP_EOI: + (void)vcpu_set_eoi(v,0L); + return 1; + case HYPERPRIVOP_SET_ITM: + (void)vcpu_set_itm(v,regs->r8); + return 1; + case HYPERPRIVOP_THASH: + (void)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))); + 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); + return 1; + case HYPERPRIVOP_GET_RR: + (void)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); + return 1; + } + return 0; +} + + +/************************************************************************** +Privileged operation instrumentation routines +**************************************************************************/ + +char *Mpriv_str[64] = { + "mov_to_rr", "mov_to_dbr", "mov_to_ibr", "mov_to_pkr", + "mov_to_pmc", "mov_to_pmd", "<0x06>", "<0x07>", + "<0x08>", "ptc_l", "ptc_g", "ptc_ga", + "ptr_d", "ptr_i", "itr_d", "itr_i", + "mov_from_rr", "mov_from_dbr", "mov_from_ibr", "mov_from_pkr", + "mov_from_pmc", "<0x15>", "<0x16>", "<0x17>", + "<0x18>", "<0x19>", "privified-thash", "privified-ttag", + "<0x1c>", "<0x1d>", "tpa", "tak", + "<0x20>", "<0x21>", "<0x22>", "<0x23>", + "mov_from_cr", "mov_from_psr", "<0x26>", "<0x27>", + "<0x28>", "<0x29>", "<0x2a>", "<0x2b>", + "mov_to_cr", "mov_to_psr", "itc_d", "itc_i", + "<0x30>", "<0x31>", "<0x32>", "<0x33>", + "ptc_e", "<0x35>", "<0x36>", "<0x37>", + "<0x38>", "<0x39>", "<0x3a>", "<0x3b>", + "<0x3c>", "<0x3d>", "<0x3e>", "<0x3f>" +}; + +#define RS "Rsvd" +char *cr_str[128] = { + "dcr","itm","iva",RS,RS,RS,RS,RS, + "pta",RS,RS,RS,RS,RS,RS,RS, + "ipsr","isr",RS,"iip","ifa","itir","iipa","ifs", + "iim","iha",RS,RS,RS,RS,RS,RS, + RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, + RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, + "lid","ivr","tpr","eoi","irr0","irr1","irr2","irr3", + "itv","pmv","cmcv",RS,RS,RS,RS,RS, + "lrr0","lrr1",RS,RS,RS,RS,RS,RS, + RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, + RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, + RS,RS,RS,RS,RS,RS,RS,RS +}; + +// FIXME: should use snprintf to ensure no buffer overflow +int dump_privop_counts(char *buf) +{ + int i, j; + UINT64 sum = 0; + char *s = buf; + + // this is ugly and should probably produce sorted output + // but it will have to do for now + sum += privcnt.mov_to_ar_imm; sum += privcnt.mov_to_ar_reg; + sum += privcnt.ssm; sum += privcnt.rsm; + sum += privcnt.rfi; sum += privcnt.bsw0; + sum += privcnt.bsw1; sum += privcnt.cover; + for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i]; + s += sprintf(s,"Privop statistics: (Total privops: %ld)\n",sum); + if (privcnt.mov_to_ar_imm) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_imm, + "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum); + if (privcnt.mov_to_ar_reg) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_reg, + "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum); + if (privcnt.mov_from_ar) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_from_ar, + "privified-mov_from_ar", (privcnt.mov_from_ar*100L)/sum); + if (privcnt.ssm) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.ssm, + "ssm", (privcnt.ssm*100L)/sum); + if (privcnt.rsm) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rsm, + "rsm", (privcnt.rsm*100L)/sum); + if (privcnt.rfi) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rfi, + "rfi", (privcnt.rfi*100L)/sum); + if (privcnt.bsw0) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw0, + "bsw0", (privcnt.bsw0*100L)/sum); + if (privcnt.bsw1) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw1, + "bsw1", (privcnt.bsw1*100L)/sum); + if (privcnt.cover) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cover, + "cover", (privcnt.cover*100L)/sum); + if (privcnt.fc) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.fc, + "privified-fc", (privcnt.fc*100L)/sum); + if (privcnt.cpuid) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cpuid, + "privified-getcpuid", (privcnt.cpuid*100L)/sum); + for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) { + if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\n"); + else s += sprintf(s,"%10d %s [%d%%]\n", privcnt.Mpriv_cnt[i], + Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum); + if (i == 0x24) { // mov from CR + s += sprintf(s," ["); + for (j=0; j < 128; j++) if (from_cr_cnt[j]) { + if (!cr_str[j]) + s += sprintf(s,"PRIVSTRING NULL!!\n"); + s += sprintf(s,"%s(%d),",cr_str[j],from_cr_cnt[j]); + } + s += sprintf(s,"]\n"); + } + else if (i == 0x2c) { // mov to CR + s += sprintf(s," ["); + for (j=0; j < 128; j++) if (to_cr_cnt[j]) { + if (!cr_str[j]) + s += sprintf(s,"PRIVSTRING NULL!!\n"); + s += sprintf(s,"%s(%d),",cr_str[j],to_cr_cnt[j]); + } + s += sprintf(s,"]\n"); + } + } + return s - buf; +} + +int zero_privop_counts(char *buf) +{ + int i, j; + char *s = buf; + + // this is ugly and should probably produce sorted output + // but it will have to do for now + privcnt.mov_to_ar_imm = 0; privcnt.mov_to_ar_reg = 0; + privcnt.mov_from_ar = 0; + privcnt.ssm = 0; privcnt.rsm = 0; + privcnt.rfi = 0; privcnt.bsw0 = 0; + privcnt.bsw1 = 0; privcnt.cover = 0; + privcnt.fc = 0; privcnt.cpuid = 0; + for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0; + for (j=0; j < 128; j++) from_cr_cnt[j] = 0; + for (j=0; j < 128; j++) to_cr_cnt[j] = 0; + s += sprintf(s,"All privop statistics zeroed\n"); + return s - buf; +} + +#ifdef PRIVOP_ADDR_COUNT + +extern struct privop_addr_count privop_addr_counter[]; + +void privop_count_addr(unsigned long iip, int inst) +{ + struct privop_addr_count *v = &privop_addr_counter[inst]; + int i; + + for (i = 0; i < PRIVOP_COUNT_NADDRS; i++) { + if (!v->addr[i]) { v->addr[i] = iip; v->count[i]++; return; } + else if (v->addr[i] == iip) { v->count[i]++; return; } + } + v->overflow++;; +} + +int dump_privop_addrs(char *buf) +{ + int i,j; + char *s = buf; + s += sprintf(s,"Privop addresses:\n"); + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + s += sprintf(s,"%s:\n",v->instname); + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) { + if (!v->addr[j]) break; + s += sprintf(s," @%p #%ld\n",v->addr[j],v->count[j]); + } + if (v->overflow) + s += sprintf(s," other #%ld\n",v->overflow); + } + return s - buf; +} + +void zero_privop_addrs(void) +{ + int i,j; + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) + v->addr[j] = v->count[j] = 0; + v->overflow = 0; + } +} +#endif + +extern unsigned long dtlb_translate_count; +extern unsigned long tr_translate_count; +extern unsigned long phys_translate_count; +extern unsigned long vhpt_translate_count; +extern unsigned long lazy_cover_count; +extern unsigned long idle_when_pending; +extern unsigned long pal_halt_light_count; +extern unsigned long context_switch_count; + +int dump_misc_stats(char *buf) +{ + char *s = buf; + s += sprintf(s,"Virtual TR translations: %d\n",tr_translate_count); + s += sprintf(s,"Virtual VHPT translations: %d\n",vhpt_translate_count); + s += sprintf(s,"Virtual DTLB translations: %d\n",dtlb_translate_count); + s += sprintf(s,"Physical translations: %d\n",phys_translate_count); + s += sprintf(s,"Idle when pending: %d\n",idle_when_pending); + s += sprintf(s,"PAL_HALT_LIGHT (no pending): %d\n",pal_halt_light_count); + s += sprintf(s,"context switches: %d\n",context_switch_count); + s += sprintf(s,"Lazy covers: %d\n",lazy_cover_count); + return s - buf; +} + +void zero_misc_stats(void) +{ + dtlb_translate_count = 0; + tr_translate_count = 0; + phys_translate_count = 0; + vhpt_translate_count = 0; + lazy_cover_count = 0; + pal_halt_light_count = 0; + idle_when_pending = 0; + context_switch_count = 0; +} + +int dump_hyperprivop_counts(char *buf) +{ + int i; + char *s = buf; + unsigned long total = 0; + for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += slow_hyperpriv_cnt[i]; + s += sprintf(s,"Slow hyperprivops (total %d):\n",total); + for (i = 1; i <= HYPERPRIVOP_MAX; i++) + if (slow_hyperpriv_cnt[i]) + s += sprintf(s,"%10d %s\n", + slow_hyperpriv_cnt[i], hyperpriv_str[i]); + total = 0; + for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += fast_hyperpriv_cnt[i]; + s += sprintf(s,"Fast hyperprivops (total %d):\n",total); + for (i = 1; i <= HYPERPRIVOP_MAX; i++) + if (fast_hyperpriv_cnt[i]) + s += sprintf(s,"%10d %s\n", + fast_hyperpriv_cnt[i], hyperpriv_str[i]); + return s - buf; +} + +void zero_hyperprivop_counts(void) +{ + int i; + for (i = 0; i <= HYPERPRIVOP_MAX; i++) slow_hyperpriv_cnt[i] = 0; + for (i = 0; i <= HYPERPRIVOP_MAX; i++) fast_hyperpriv_cnt[i] = 0; +} + +#define TMPBUFLEN 8*1024 +int dump_privop_counts_to_user(char __user *ubuf, int len) +{ + char buf[TMPBUFLEN]; + int n = dump_privop_counts(buf); + + n += dump_hyperprivop_counts(buf + n); + n += dump_reflect_counts(buf + n); +#ifdef PRIVOP_ADDR_COUNT + n += dump_privop_addrs(buf + n); +#endif + n += dump_misc_stats(buf + n); + if (len < TMPBUFLEN) return -1; + if (__copy_to_user(ubuf,buf,n)) return -1; + return n; +} + +int zero_privop_counts_to_user(char __user *ubuf, int len) +{ + char buf[TMPBUFLEN]; + int n = zero_privop_counts(buf); + + zero_hyperprivop_counts(); +#ifdef PRIVOP_ADDR_COUNT + zero_privop_addrs(); +#endif + zero_misc_stats(); + zero_reflect_counts(); + if (len < TMPBUFLEN) return -1; + if (__copy_to_user(ubuf,buf,n)) return -1; + return n; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/process.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/process.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,749 @@ +/* + * Miscellaneous process/domain related routines + * + * Copyright (C) 2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/smp.h> +#include <asm/ptrace.h> +#include <xen/delay.h> + +#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ +#include <asm/sal.h> /* FOR struct ia64_sal_retval */ + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/desc.h> +//#include <asm/ldt.h> +#include <xen/irq.h> +#include <xen/event.h> +#include <asm/regionreg.h> +#include <asm/privop.h> +#include <asm/vcpu.h> +#include <asm/ia64_int.h> +#include <asm/dom_fw.h> +#include "hpsim_ssc.h" + +extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); +extern struct ia64_sal_retval pal_emulator_static(UINT64); +extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); + +extern unsigned long dom0_start, dom0_size; + +#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT) +// note IA64_PSR_PK removed from following, why is this necessary? +#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \ + IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \ + IA64_PSR_IT | IA64_PSR_BN) + +#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \ + IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \ + IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \ + IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \ + IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ + IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) + +#define PSCB(x,y) VCPU(x,y) +#define PSCBX(x,y) x->arch.y + +extern unsigned long vcpu_verbose; + +long do_iopl(domid_t domain, unsigned int new_io_pl) +{ + dummy(); + return 0; +} + +void schedule_tail(struct vcpu *next) +{ + unsigned long rr7; + //printk("current=%lx,shared_info=%lx\n",current,current->vcpu_info); + //printk("next=%lx,shared_info=%lx\n",next,next->vcpu_info); +#ifdef CONFIG_VTI + /* rr7 will be postponed to last point when resuming back to guest */ + vmx_load_all_rr(current); +#else // CONFIG_VTI + if (rr7 = load_region_regs(current)) { + printk("schedule_tail: change to rr7 not yet implemented\n"); + } +#endif // CONFIG_VTI +} + +void tdpfoo(void) { } + +// given a domain virtual address, pte and pagesize, extract the metaphysical +// address, convert the pte for a physical address for (possibly different) +// Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use +// PAGE_SIZE!) +unsigned long translate_domain_pte(unsigned long pteval, + unsigned long address, unsigned long itir) +{ + struct domain *d = current->domain; + unsigned long mask, pteval2, mpaddr; + unsigned long lookup_domain_mpa(struct domain *,unsigned long); + extern struct domain *dom0; + extern unsigned long dom0_start, dom0_size; + + // FIXME address had better be pre-validated on insert + mask = (1L << ((itir >> 2) & 0x3f)) - 1; + mpaddr = ((pteval & _PAGE_PPN_MASK) & ~mask) | (address & mask); + if (d == dom0) { + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + //printk("translate_domain_pte: out-of-bounds dom0 mpaddr %p! itc=%lx...\n",mpaddr,ia64_get_itc()); + tdpfoo(); + } + } + else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) { + printf("translate_domain_pte: bad mpa=%p (> %p),vadr=%p,pteval=%p,itir=%p\n", + mpaddr,d->max_pages<<PAGE_SHIFT,address,pteval,itir); + tdpfoo(); + } + pteval2 = lookup_domain_mpa(d,mpaddr); + pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits + pteval2 |= _PAGE_PL_2; // force PL0->2 (PL3 is unaffected) + pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2; + return pteval2; +} + +// given a current domain metaphysical address, return the physical address +unsigned long translate_domain_mpaddr(unsigned long mpaddr) +{ + extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); + unsigned long pteval; + + if (current->domain == dom0) { + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr); + tdpfoo(); + } + } + pteval = lookup_domain_mpa(current->domain,mpaddr); + return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK)); +} + +unsigned long slow_reflect_count[0x80] = { 0 }; +unsigned long fast_reflect_count[0x80] = { 0 }; + +#define inc_slow_reflect_count(vec) slow_reflect_count[vec>>8]++; + +void zero_reflect_counts(void) +{ + int i; + for (i=0; i<0x80; i++) slow_reflect_count[i] = 0; + for (i=0; i<0x80; i++) fast_reflect_count[i] = 0; +} + +int dump_reflect_counts(char *buf) +{ + int i,j,cnt; + char *s = buf; + + s += sprintf(s,"Slow reflections by vector:\n"); + for (i = 0, j = 0; i < 0x80; i++) { + if (cnt = slow_reflect_count[i]) { + s += sprintf(s,"0x%02x00:%10d, ",i,cnt); + if ((j++ & 3) == 3) s += sprintf(s,"\n"); + } + } + if (j & 3) s += sprintf(s,"\n"); + s += sprintf(s,"Fast reflections by vector:\n"); + for (i = 0, j = 0; i < 0x80; i++) { + if (cnt = fast_reflect_count[i]) { + s += sprintf(s,"0x%02x00:%10d, ",i,cnt); + if ((j++ & 3) == 3) s += sprintf(s,"\n"); + } + } + if (j & 3) s += sprintf(s,"\n"); + return s - buf; +} + +void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector) +{ + unsigned long vcpu_get_ipsr_int_state(struct vcpu *,unsigned long); + unsigned long vcpu_get_rr_ve(struct vcpu *,unsigned long); + struct domain *d = current->domain; + struct vcpu *v = current; + + if (vector == IA64_EXTINT_VECTOR) { + + extern unsigned long vcpu_verbose, privop_trace; + static first_extint = 1; + if (first_extint) { + printf("Delivering first extint to domain: ifa=%p, isr=%p, itir=%p, iip=%p\n",ifa,isr,itiriim,regs->cr_iip); + //privop_trace = 1; vcpu_verbose = 1; + first_extint = 0; + } + } + if (!PSCB(v,interrupt_collection_enabled)) { + if (!(PSCB(v,ipsr) & IA64_PSR_DT)) { + panic_domain(regs,"psr.dt off, trying to deliver nested dtlb!\n"); + } + vector &= ~0xf; + if (vector != IA64_DATA_TLB_VECTOR && + vector != IA64_ALT_DATA_TLB_VECTOR && + vector != IA64_VHPT_TRANS_VECTOR) { +panic_domain(regs,"psr.ic off, delivering fault=%lx,ipsr=%p,iip=%p,ifa=%p,isr=%p,PSCB.iip=%p\n", + vector,regs->cr_ipsr,regs->cr_iip,ifa,isr,PSCB(v,iip)); + + } +//printf("Delivering NESTED DATA TLB fault\n"); + vector = IA64_DATA_NESTED_TLB_VECTOR; + regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL; + regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; +// NOTE: nested trap must NOT pass PSCB address + //regs->r31 = (unsigned long) &PSCB(v); + inc_slow_reflect_count(vector); + return; + + } + if ((vector & 0xf) == IA64_FORCED_IFA) + ifa = PSCB(v,tmp[0]); + vector &= ~0xf; + PSCB(v,ifa) = ifa; + if (vector < IA64_DATA_NESTED_TLB_VECTOR) /* VHPT miss, TLB miss, Alt TLB miss */ + vcpu_thash(v,ifa,&PSCB(current,iha)); + PSCB(v,unat) = regs->ar_unat; // not sure if this is really needed? + PSCB(v,precover_ifs) = regs->cr_ifs; + vcpu_bsw0(v); + PSCB(v,ipsr) = vcpu_get_ipsr_int_state(v,regs->cr_ipsr); + if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) + PSCB(v,iim) = itiriim; + else PSCB(v,itir) = vcpu_get_itir_on_fault(v,ifa); + PSCB(v,isr) = isr; // this is unnecessary except for interrupts! + PSCB(v,iip) = regs->cr_iip; + PSCB(v,ifs) = 0; + PSCB(v,incomplete_regframe) = 0; + + regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL; + regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; +#ifdef CONFIG_SMP +#warning "SMP FIXME: sharedinfo doesn't handle smp yet, need page per vcpu" +#endif + regs->r31 = &(((mapped_regs_t *)SHARED_ARCHINFO_ADDR)->ipsr); + + PSCB(v,interrupt_delivery_enabled) = 0; + PSCB(v,interrupt_collection_enabled) = 0; + + inc_slow_reflect_count(vector); +} + +void foodpi(void) {} + +unsigned long pending_false_positive = 0; + +// ONLY gets called from ia64_leave_kernel +// ONLY call with interrupts disabled?? (else might miss one?) +// NEVER successful if already reflecting a trap/fault because psr.i==0 +void deliver_pending_interrupt(struct pt_regs *regs) +{ + struct domain *d = current->domain; + struct vcpu *v = current; + // FIXME: Will this work properly if doing an RFI??? + if (!is_idle_task(d) && user_mode(regs)) { + //vcpu_poke_timer(v); + if (vcpu_deliverable_interrupts(v)) { + unsigned long isr = regs->cr_ipsr & IA64_PSR_RI; + if (vcpu_timer_pending_early(v)) +printf("*#*#*#* about to deliver early timer to domain %d!!!\n",v->domain->domain_id); + reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR); + } + else if (PSCB(v,pending_interruption)) + ++pending_false_positive; + } +} +unsigned long lazy_cover_count = 0; + +int handle_lazy_cover(struct vcpu *v, unsigned long isr, struct pt_regs *regs) +{ + if (!PSCB(v,interrupt_collection_enabled)) { + PSCB(v,ifs) = regs->cr_ifs; + PSCB(v,incomplete_regframe) = 1; + regs->cr_ifs = 0; + lazy_cover_count++; + return(1); // retry same instruction with cr.ifs off + } + return(0); +} + +void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir) +{ + unsigned long iip = regs->cr_iip; + // FIXME should validate address here + unsigned long pteval; + unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL); + IA64FAULT fault; + + if ((isr & IA64_ISR_IR) && handle_lazy_cover(current, isr, regs)) return; + if ((isr & IA64_ISR_SP) + || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) + { + /* + * This fault was due to a speculative load or lfetch.fault, set the "ed" + * bit in the psr to ensure forward progress. (Target register will get a + * NaT for ld.s, lfetch will be canceled.) + */ + ia64_psr(regs)->ed = 1; + return; + } + + fault = vcpu_translate(current,address,is_data,&pteval,&itir); + if (fault == IA64_NO_FAULT) + { + pteval = translate_domain_pte(pteval,address,itir); + vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,(itir>>2)&0x3f); + return; + } + else if (IS_VMM_ADDRESS(iip)) + { + if (!ia64_done_with_exception(regs)) { + // should never happen. If it does, region 0 addr may + // indicate a bad xen pointer + printk("*** xen_handle_domain_access: exception table" + " lookup failed, iip=%p, addr=%p, spinning...\n", + iip,address); + panic_domain(regs,"*** xen_handle_domain_access: exception table" + " lookup failed, iip=%p, addr=%p, spinning...\n", + iip,address); + } + return; + } + + reflect_interruption(address, isr, 0, regs, fault); +} + +void +ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, + unsigned long iim, unsigned long itir, unsigned long arg5, + unsigned long arg6, unsigned long arg7, unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long code, error = isr; + char buf[128]; + int result, sig; + static const char *reason[] = { + "IA-64 Illegal Operation fault", + "IA-64 Privileged Operation fault", + "IA-64 Privileged Register fault", + "IA-64 Reserved Register/Field fault", + "Disabled Instruction Set Transition fault", + "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", + "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", + "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" + }; +#if 0 +printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", + vector, ifa, regs->cr_iip, regs->cr_ipsr, isr); +#endif + + if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { + /* + * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel + * the lfetch. + */ + ia64_psr(regs)->ed = 1; + printf("ia64_fault: handled lfetch.fault\n"); + return; + } + + switch (vector) { + case 24: /* General Exception */ + code = (isr >> 4) & 0xf; + sprintf(buf, "General Exception: %s%s", reason[code], + (code == 3) ? ((isr & (1UL << 37)) + ? " (RSE access)" : " (data access)") : ""); + if (code == 8) { +# ifdef CONFIG_IA64_PRINT_HAZARDS + printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n", + current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, + regs->pr); +# endif + printf("ia64_fault: returning on hazard\n"); + return; + } + break; + + case 25: /* Disabled FP-Register */ + if (isr & 2) { + //disabled_fph_fault(regs); + //return; + } + sprintf(buf, "Disabled FPL fault---not supposed to happen!"); + break; + + case 26: /* NaT Consumption */ + if (user_mode(regs)) { + void *addr; + + if (((isr >> 4) & 0xf) == 2) { + /* NaT page consumption */ + //sig = SIGSEGV; + //code = SEGV_ACCERR; + addr = (void *) ifa; + } else { + /* register NaT consumption */ + //sig = SIGILL; + //code = ILL_ILLOPN; + addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + } + //siginfo.si_signo = sig; + //siginfo.si_code = code; + //siginfo.si_errno = 0; + //siginfo.si_addr = addr; + //siginfo.si_imm = vector; + //siginfo.si_flags = __ISR_VALID; + //siginfo.si_isr = isr; + //force_sig_info(sig, &siginfo, current); + //return; + } //else if (ia64_done_with_exception(regs)) + //return; + sprintf(buf, "NaT consumption"); + break; + + case 31: /* Unsupported Data Reference */ + if (user_mode(regs)) { + //siginfo.si_signo = SIGILL; + //siginfo.si_code = ILL_ILLOPN; + //siginfo.si_errno = 0; + //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + //siginfo.si_imm = vector; + //siginfo.si_flags = __ISR_VALID; + //siginfo.si_isr = isr; + //force_sig_info(SIGILL, &siginfo, current); + //return; + } + sprintf(buf, "Unsupported data reference"); + break; + + case 29: /* Debug */ + case 35: /* Taken Branch Trap */ + case 36: /* Single Step Trap */ + //if (fsys_mode(current, regs)) {} + switch (vector) { + case 29: + //siginfo.si_code = TRAP_HWBKPT; +#ifdef CONFIG_ITANIUM + /* + * Erratum 10 (IFA may contain incorrect address) now has + * "NoFix" status. There are no plans for fixing this. + */ + if (ia64_psr(regs)->is == 0) + ifa = regs->cr_iip; +#endif + break; + case 35: ifa = 0; break; + case 36: ifa = 0; break; + //case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; + //case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; + } + //siginfo.si_signo = SIGTRAP; + //siginfo.si_errno = 0; + //siginfo.si_addr = (void *) ifa; + //siginfo.si_imm = 0; + //siginfo.si_flags = __ISR_VALID; + //siginfo.si_isr = isr; + //force_sig_info(SIGTRAP, &siginfo, current); + //return; + + case 32: /* fp fault */ + case 33: /* fp trap */ + //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); + //if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { + //siginfo.si_signo = SIGFPE; + //siginfo.si_errno = 0; + //siginfo.si_code = FPE_FLTINV; + //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + //siginfo.si_flags = __ISR_VALID; + //siginfo.si_isr = isr; + //siginfo.si_imm = 0; + //force_sig_info(SIGFPE, &siginfo, current); + //} + //return; + sprintf(buf, "FP fault/trap"); + break; + + case 34: + if (isr & 0x2) { + /* Lower-Privilege Transfer Trap */ + /* + * Just clear PSR.lp and then return immediately: all the + * interesting work (e.g., signal delivery is done in the kernel + * exit path). + */ + //ia64_psr(regs)->lp = 0; + //return; + sprintf(buf, "Lower-Privilege Transfer trap"); + } else { + /* Unimplemented Instr. Address Trap */ + if (user_mode(regs)) { + //siginfo.si_signo = SIGILL; + //siginfo.si_code = ILL_BADIADDR; + //siginfo.si_errno = 0; + //siginfo.si_flags = 0; + //siginfo.si_isr = 0; + //siginfo.si_imm = 0; + //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + //force_sig_info(SIGILL, &siginfo, current); + //return; + } + sprintf(buf, "Unimplemented Instruction Address fault"); + } + break; + + case 45: + printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n"); + printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", + regs->cr_iip, ifa, isr); + //force_sig(SIGSEGV, current); + break; + + case 46: + printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n"); + printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", + regs->cr_iip, ifa, isr, iim); + //force_sig(SIGSEGV, current); + return; + + case 47: + sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); + break; + + default: + sprintf(buf, "Fault %lu", vector); + break; + } + //die_if_kernel(buf, regs, error); +printk("ia64_fault: %s: reflecting\n",buf); +reflect_interruption(ifa,isr,iim,regs,IA64_GENEX_VECTOR); +//while(1); + //force_sig(SIGILL, current); +} + +unsigned long running_on_sim = 0; + +void +do_ssc(unsigned long ssc, struct pt_regs *regs) +{ + extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); + unsigned long arg0, arg1, arg2, arg3, retval; + char buf[2]; +/**/ static int last_fd, last_count; // FIXME FIXME FIXME +/**/ // BROKEN FOR MULTIPLE DOMAINS & SMP +/**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat; + extern unsigned long vcpu_verbose, privop_trace; + + arg0 = vcpu_get_gr(current,32); + switch(ssc) { + case SSC_PUTCHAR: + buf[0] = arg0; + buf[1] = '\0'; + printf(buf); + break; + case SSC_GETCHAR: + retval = ia64_ssc(0,0,0,0,ssc); + vcpu_set_gr(current,8,retval); + break; + case SSC_WAIT_COMPLETION: + if (arg0) { // metaphysical address + + arg0 = translate_domain_mpaddr(arg0); +/**/ stat = (struct ssc_disk_stat *)__va(arg0); +///**/ if (stat->fd == last_fd) stat->count = last_count; +/**/ stat->count = last_count; +//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count); +///**/ retval = ia64_ssc(arg0,0,0,0,ssc); +/**/ retval = 0; + } + else retval = -1L; + vcpu_set_gr(current,8,retval); + break; + case SSC_OPEN: + arg1 = vcpu_get_gr(current,33); // access rights +if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; } + if (arg0) { // metaphysical address + arg0 = translate_domain_mpaddr(arg0); + retval = ia64_ssc(arg0,arg1,0,0,ssc); + } + else retval = -1L; + vcpu_set_gr(current,8,retval); + break; + case SSC_WRITE: + case SSC_READ: +//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n"); + arg1 = vcpu_get_gr(current,33); + arg2 = vcpu_get_gr(current,34); + arg3 = vcpu_get_gr(current,35); + if (arg2) { // metaphysical address of descriptor + struct ssc_disk_req *req; + unsigned long mpaddr, paddr; + long len; + + arg2 = translate_domain_mpaddr(arg2); + req = (struct disk_req *)__va(arg2); + req->len &= 0xffffffffL; // avoid strange bug + len = req->len; +/**/ last_fd = arg1; +/**/ last_count = len; + mpaddr = req->addr; +//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len); + retval = 0; + if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) { + // do partial page first + req->addr = translate_domain_mpaddr(mpaddr); + req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK); + len -= req->len; mpaddr += req->len; + retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); + arg3 += req->len; // file offset +/**/ last_stat.fd = last_fd; +/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); +//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval); + } + if (retval >= 0) while (len > 0) { + req->addr = translate_domain_mpaddr(mpaddr); + req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len; + len -= PAGE_SIZE; mpaddr += PAGE_SIZE; + retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); + arg3 += req->len; // file offset +// TEMP REMOVED AGAIN arg3 += req->len; // file offset +/**/ last_stat.fd = last_fd; +/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); +//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval); + } + // set it back to the original value + req->len = last_count; + } + else retval = -1L; + vcpu_set_gr(current,8,retval); +//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval); + break; + case SSC_CONNECT_INTERRUPT: + arg1 = vcpu_get_gr(current,33); + arg2 = vcpu_get_gr(current,34); + arg3 = vcpu_get_gr(current,35); + if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; } + (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc); + break; + case SSC_NETDEV_PROBE: + vcpu_set_gr(current,8,-1L); + break; + default: + printf("ia64_handle_break: bad ssc code %lx, iip=%p, b0=%p... spinning\n",ssc,regs->cr_iip,regs->b0); + while(1); + break; + } + vcpu_increment_iip(current); +} + +int first_break = 1; + +void +ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) +{ + struct domain *d = (struct domain *) current->domain; + struct vcpu *v = (struct domain *) current; + extern unsigned long running_on_sim; + + if (first_break) { + if (platform_is_hp_ski()) running_on_sim = 1; + else running_on_sim = 0; + first_break = 0; + } + if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant + if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); + else do_ssc(vcpu_get_gr(current,36), regs); + } + else if (iim == d->arch.breakimm) { + if (ia64_hypercall(regs)) + vcpu_increment_iip(current); + } + else if (!PSCB(v,interrupt_collection_enabled)) { + if (ia64_hyperprivop(iim,regs)) + vcpu_increment_iip(current); + } + else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR); +} + +void +ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir) +{ + IA64FAULT vector; + struct domain *d = current->domain; + struct vcpu *v = current; + // FIXME: no need to pass itir in to this routine as we need to + // compute the virtual itir anyway (based on domain's RR.ps) + // AND ACTUALLY reflect_interruption doesn't use it anyway! + itir = vcpu_get_itir_on_fault(v,ifa); + vector = priv_emulate(current,regs,isr); + if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) { + reflect_interruption(ifa,isr,itir,regs,vector); + } +} + +#define INTR_TYPE_MAX 10 +UINT64 int_counts[INTR_TYPE_MAX]; + +void +ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector) +{ + struct domain *d = (struct domain *) current->domain; + struct vcpu *v = (struct domain *) current; + unsigned long check_lazy_cover = 0; + unsigned long psr = regs->cr_ipsr; + unsigned long itir = vcpu_get_itir_on_fault(v,ifa); + + if (!(psr & IA64_PSR_CPL)) { + printk("ia64_handle_reflection: reflecting with priv=0!!\n"); + } + // FIXME: no need to pass itir in to this routine as we need to + // compute the virtual itir anyway (based on domain's RR.ps) + // AND ACTUALLY reflect_interruption doesn't use it anyway! + itir = vcpu_get_itir_on_fault(v,ifa); + switch(vector) { + case 8: + vector = IA64_DIRTY_BIT_VECTOR; break; + case 9: + vector = IA64_INST_ACCESS_BIT_VECTOR; break; + case 10: + check_lazy_cover = 1; + vector = IA64_DATA_ACCESS_BIT_VECTOR; break; + case 20: + check_lazy_cover = 1; + vector = IA64_PAGE_NOT_PRESENT_VECTOR; break; + case 22: + vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break; + case 23: + check_lazy_cover = 1; + vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break; + case 25: + vector = IA64_DISABLED_FPREG_VECTOR; + break; + case 26: +printf("*** NaT fault... attempting to handle as privop\n"); +printf("isr=%p, ifa=%p,iip=%p,ipsr=%p\n",isr,ifa,regs->cr_iip,psr); + vector = priv_emulate(v,regs,isr); + if (vector == IA64_NO_FAULT) { +printf("*** Handled privop masquerading as NaT fault\n"); + return; + } + vector = IA64_NAT_CONSUMPTION_VECTOR; break; + case 27: +//printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc()); + itir = iim; + vector = IA64_SPECULATION_VECTOR; break; + case 30: + // FIXME: Should we handle unaligned refs in Xen?? + vector = IA64_UNALIGNED_REF_VECTOR; break; + default: + printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector); + while(vector); + return; + } + if (check_lazy_cover && (isr & IA64_ISR_IR) && handle_lazy_cover(v, isr, regs)) return; + reflect_interruption(ifa,isr,itir,regs,vector); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/regionreg.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/regionreg.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,376 @@ +/* + * Region register and region id management + * + * Copyright (C) 2001-2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx + * Bret Mckee (bret.mckee@xxxxxx) + * + */ + + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <asm/page.h> +#include <asm/regionreg.h> +#include <asm/vhpt.h> +#include <asm/vcpu.h> +extern void ia64_new_rr7(unsigned long rid,void *shared_info, void *shared_arch_info); + + +#define IA64_MIN_IMPL_RID_BITS (IA64_MIN_IMPL_RID_MSB+1) +#define IA64_MAX_IMPL_RID_BITS 24 + +#define MIN_RIDS (1 << IA64_MIN_IMPL_RID_BITS) +#define MIN_RID_MAX (MIN_RIDS - 1) +#define MIN_RID_MASK (MIN_RIDS - 1) +#define MAX_RIDS (1 << (IA64_MAX_IMPL_RID_BITS)) +#define MAX_RID (MAX_RIDS - 1) +#define MAX_RID_BLOCKS (1 << (IA64_MAX_IMPL_RID_BITS-IA64_MIN_IMPL_RID_BITS)) +#define RIDS_PER_RIDBLOCK MIN_RIDS + +#if 0 +// following already defined in include/asm-ia64/gcc_intrin.h +// it should probably be ifdef'd out from there to ensure all region +// register usage is encapsulated in this file +static inline unsigned long +ia64_get_rr (unsigned long rr) +{ + unsigned long r; + __asm__ __volatile__ (";;mov %0=rr[%1];;":"=r"(r):"r"(rr):"memory"); + return r; +} + +static inline void +ia64_set_rr (unsigned long rr, unsigned long rrv) +{ + __asm__ __volatile__ (";;mov rr[%0]=%1;;"::"r"(rr),"r"(rrv):"memory"); +} +#endif + +// use this to allocate a rid out of the "Xen reserved rid block" +unsigned long allocate_reserved_rid(void) +{ + static unsigned long currentrid = XEN_DEFAULT_RID; + unsigned long t = currentrid; + + unsigned long max = RIDS_PER_RIDBLOCK; + + if (++currentrid >= max) return(-1UL); + return t; +} + + +// returns -1 if none available +unsigned long allocate_metaphysical_rr(void) +{ + ia64_rr rrv; + + rrv.rid = allocate_reserved_rid(); + rrv.ps = PAGE_SHIFT; + rrv.ve = 0; + return rrv.rrval; +} + +int deallocate_metaphysical_rid(unsigned long rid) +{ + // fix this when the increment allocation mechanism is fixed. + return 1; +} + +/************************************* + Region Block setup/management +*************************************/ + +static int implemented_rid_bits = 0; +static struct domain *ridblock_owner[MAX_RID_BLOCKS] = { 0 }; + +void get_impl_rid_bits(void) +{ + // FIXME (call PAL) +//#ifdef CONFIG_MCKINLEY + implemented_rid_bits = IA64_MAX_IMPL_RID_BITS; +//#else +//#error "rid ranges won't work on Merced" +//#endif + if (implemented_rid_bits <= IA64_MIN_IMPL_RID_BITS || + implemented_rid_bits > IA64_MAX_IMPL_RID_BITS) + BUG(); +} + + +/* + * Allocate a power-of-two-sized chunk of region id space -- one or more + * "rid blocks" + */ +int allocate_rid_range(struct domain *d, unsigned long ridbits) +{ + int i, j, n_rid_blocks; + + if (implemented_rid_bits == 0) get_impl_rid_bits(); + + if (ridbits >= IA64_MAX_IMPL_RID_BITS) + ridbits = IA64_MAX_IMPL_RID_BITS - 1; + + if (ridbits < IA64_MIN_IMPL_RID_BITS) + ridbits = IA64_MIN_IMPL_RID_BITS; + + // convert to rid_blocks and find one + n_rid_blocks = ridbits - IA64_MIN_IMPL_RID_BITS + 1; + + // skip over block 0, reserved for "meta-physical mappings (and Xen)" + for (i = n_rid_blocks; i < MAX_RID_BLOCKS; i += n_rid_blocks) { + if (ridblock_owner[i] == NULL) { + for (j = i; j < i + n_rid_blocks; ++j) { + if (ridblock_owner[j]) break; + } + if (ridblock_owner[j] == NULL) break; + } + } + + if (i >= MAX_RID_BLOCKS) return 0; + + // found an unused block: + // (i << min_rid_bits) <= rid < ((i + n) << min_rid_bits) + // mark this block as owned + for (j = i; j < i + n_rid_blocks; ++j) ridblock_owner[j] = d; + + // setup domain struct + d->arch.rid_bits = ridbits; + d->arch.starting_rid = i << IA64_MIN_IMPL_RID_BITS; d->arch.ending_rid = (i+n_rid_blocks) << IA64_MIN_IMPL_RID_BITS; +printf("###allocating rid_range, domain %p: starting_rid=%lx, ending_rid=%lx\n", +d,d->arch.starting_rid, d->arch.ending_rid); + + return 1; +} + + +int deallocate_rid_range(struct domain *d) +{ + int i; + int rid_block_end = d->arch.ending_rid >> IA64_MIN_IMPL_RID_BITS; + int rid_block_start = d->arch.starting_rid >> IA64_MIN_IMPL_RID_BITS; + + return 1; // KLUDGE ALERT + // + // not all domains will have allocated RIDs (physical mode loaders for instance) + // + if (d->arch.rid_bits == 0) return 1; + +#ifdef DEBUG + for (i = rid_block_start; i < rid_block_end; ++i) { + ASSERT(ridblock_owner[i] == d); + } +#endif + + for (i = rid_block_start; i < rid_block_end; ++i) + ridblock_owner[i] = NULL; + + d->arch.rid_bits = 0; + d->arch.starting_rid = 0; + d->arch.ending_rid = 0; + return 1; +} + + +static inline void +set_rr_no_srlz(unsigned long rr, unsigned long rrval) +{ + ia64_set_rr(rr, vmMangleRID(rrval)); +} + +void +set_rr(unsigned long rr, unsigned long rrval) +{ + ia64_set_rr(rr, vmMangleRID(rrval)); + ia64_srlz_d(); +} + +unsigned long +get_rr(unsigned long rr) +{ + return vmUnmangleRID(ia64_get_rr(rr)); +} + +static inline int validate_page_size(unsigned long ps) +{ + switch(ps) { + case 12: case 13: case 14: case 16: case 18: + case 20: case 22: case 24: case 26: case 28: + return 1; + default: + return 0; + } +} + +// validates and changes a single region register +// in the currently executing domain +// Passing a value of -1 is a (successful) no-op +// NOTE: DOES NOT SET VCPU's rrs[x] value!! +int set_one_rr(unsigned long rr, unsigned long val) +{ + struct vcpu *v = current; + unsigned long rreg = REGION_NUMBER(rr); + ia64_rr rrv, newrrv, memrrv; + unsigned long newrid; + + if (val == -1) return 1; + + rrv.rrval = val; + newrrv.rrval = 0; + newrid = v->arch.starting_rid + rrv.rid; + + if (newrid > v->arch.ending_rid) { + printk("can't set rr%d to %lx, starting_rid=%lx," + "ending_rid=%lx, val=%lx\n", rreg, newrid, + v->arch.starting_rid,v->arch.ending_rid,val); + return 0; + } + +#ifdef CONFIG_VTI + memrrv.rrval = rrv.rrval; + if (rreg == 7) { + newrrv.rid = newrid; + newrrv.ve = VHPT_ENABLED_REGION_7; + newrrv.ps = IA64_GRANULE_SHIFT; + ia64_new_rr7(vmMangleRID(newrrv.rrval),v->vcpu_info, + v->vcpu_info->arch.privregs); + } + else { + newrrv.rid = newrid; + // FIXME? region 6 needs to be uncached for EFI to work + if (rreg == 6) newrrv.ve = VHPT_ENABLED_REGION_7; + else newrrv.ve = VHPT_ENABLED_REGION_0_TO_6; + newrrv.ps = PAGE_SHIFT; + if (rreg == 0) v->arch.metaphysical_saved_rr0 = newrrv.rrval; + set_rr(rr,newrrv.rrval); + } +#else + memrrv.rrval = rrv.rrval; + newrrv.rid = newrid; + newrrv.ve = 1; // VHPT now enabled for region 7!! + newrrv.ps = PAGE_SHIFT; + if (rreg == 0) v->arch.metaphysical_saved_rr0 = newrrv.rrval; + if (rreg == 7) ia64_new_rr7(vmMangleRID(newrrv.rrval),v->vcpu_info, + v->vcpu_info->arch.privregs); + else set_rr(rr,newrrv.rrval); +#endif + return 1; +} + +// set rr0 to the passed rid (for metaphysical mode so don't use domain offset +int set_metaphysical_rr0(void) +{ + struct vcpu *v = current; + ia64_rr rrv; + +// rrv.ve = 1; FIXME: TURN ME BACK ON WHEN VHPT IS WORKING + set_rr(0,v->arch.metaphysical_rr0); +} + +// validates/changes region registers 0-6 in the currently executing domain +// Note that this is the one and only SP API (other than executing a privop) +// for a domain to use to change region registers +int set_all_rr( u64 rr0, u64 rr1, u64 rr2, u64 rr3, + u64 rr4, u64 rr5, u64 rr6, u64 rr7) +{ + if (!set_one_rr(0x0000000000000000L, rr0)) return 0; + if (!set_one_rr(0x2000000000000000L, rr1)) return 0; + if (!set_one_rr(0x4000000000000000L, rr2)) return 0; + if (!set_one_rr(0x6000000000000000L, rr3)) return 0; + if (!set_one_rr(0x8000000000000000L, rr4)) return 0; + if (!set_one_rr(0xa000000000000000L, rr5)) return 0; + if (!set_one_rr(0xc000000000000000L, rr6)) return 0; + if (!set_one_rr(0xe000000000000000L, rr7)) return 0; + return 1; +} + +void init_all_rr(struct vcpu *v) +{ + ia64_rr rrv; + + rrv.rrval = 0; + rrv.rrval = v->domain->arch.metaphysical_rr0; + rrv.ps = PAGE_SHIFT; + rrv.ve = 1; +if (!v->vcpu_info) { printf("Stopping in init_all_rr\n"); dummy(); } + VCPU(v,rrs[0]) = -1; + VCPU(v,rrs[1]) = rrv.rrval; + VCPU(v,rrs[2]) = rrv.rrval; + VCPU(v,rrs[3]) = rrv.rrval; + VCPU(v,rrs[4]) = rrv.rrval; + VCPU(v,rrs[5]) = rrv.rrval; + rrv.ve = 0; + VCPU(v,rrs[6]) = rrv.rrval; +// v->shared_info->arch.rrs[7] = rrv.rrval; +} + + +/* XEN/ia64 INTERNAL ROUTINES */ + +unsigned long physicalize_rid(struct vcpu *v, unsigned long rrval) +{ + ia64_rr rrv; + + rrv.rrval = rrval; + rrv.rid += v->arch.starting_rid; + return rrv.rrval; +} + +unsigned long +virtualize_rid(struct vcpu *v, unsigned long rrval) +{ + ia64_rr rrv; + + rrv.rrval = rrval; + rrv.rid -= v->arch.starting_rid; + return rrv.rrval; +} + +// loads a thread's region register (0-6) state into +// the real physical region registers. Returns the +// (possibly mangled) bits to store into rr7 +// iff it is different than what is currently in physical +// rr7 (because we have to to assembly and physical mode +// to change rr7). If no change to rr7 is required, returns 0. +// +unsigned long load_region_regs(struct vcpu *v) +{ + unsigned long rr0, rr1,rr2, rr3, rr4, rr5, rr6, rr7; + // TODO: These probably should be validated + unsigned long bad = 0; + + if (VCPU(v,metaphysical_mode)) { + ia64_rr rrv; + + rrv.rrval = 0; + rrv.rid = v->domain->arch.metaphysical_rr0; + rrv.ps = PAGE_SHIFT; + rrv.ve = 1; + rr0 = rrv.rrval; + set_rr_no_srlz(0x0000000000000000L, rr0); + ia64_srlz_d(); + } + else { + rr0 = VCPU(v,rrs[0]); + if (!set_one_rr(0x0000000000000000L, rr0)) bad |= 1; + } + rr1 = VCPU(v,rrs[1]); + rr2 = VCPU(v,rrs[2]); + rr3 = VCPU(v,rrs[3]); + rr4 = VCPU(v,rrs[4]); + rr5 = VCPU(v,rrs[5]); + rr6 = VCPU(v,rrs[6]); + rr7 = VCPU(v,rrs[7]); + if (!set_one_rr(0x2000000000000000L, rr1)) bad |= 2; + if (!set_one_rr(0x4000000000000000L, rr2)) bad |= 4; + if (!set_one_rr(0x6000000000000000L, rr3)) bad |= 8; + if (!set_one_rr(0x8000000000000000L, rr4)) bad |= 0x10; + if (!set_one_rr(0xa000000000000000L, rr5)) bad |= 0x20; + if (!set_one_rr(0xc000000000000000L, rr6)) bad |= 0x40; + if (!set_one_rr(0xe000000000000000L, rr7)) bad |= 0x80; + if (bad) { + panic_domain(0,"load_region_regs: can't set! bad=%lx\n",bad); + } + return 0; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/sn_console.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/sn_console.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,84 @@ +/* + * C-Brick Serial Port (and console) driver for SGI Altix machines. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include <asm/acpi.h> +#include <asm/sn/sn_sal.h> +#include <xen/serial.h> + +void sn_putc(struct serial_port *, char); + +static struct uart_driver sn_sal_console = { + .putc = sn_putc, +}; + +/** + * early_sn_setup - early setup routine for SN platforms + * + * pulled from arch/ia64/sn/kernel/setup.c + */ +static void __init early_sn_setup(void) +{ + efi_system_table_t *efi_systab; + efi_config_table_t *config_tables; + struct ia64_sal_systab *sal_systab; + struct ia64_sal_desc_entry_point *ep; + char *p; + int i, j; + + /* + * Parse enough of the SAL tables to locate the SAL entry point. Since, console + * IO on SN2 is done via SAL calls, early_printk won't work without this. + * + * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c. + * Any changes to those file may have to be made hereas well. + */ + efi_systab = (efi_system_table_t *) __va(ia64_boot_param->efi_systab); + config_tables = __va(efi_systab->tables); + for (i = 0; i < efi_systab->nr_tables; i++) { + if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == + 0) { + sal_systab = __va(config_tables[i].table); + p = (char *)(sal_systab + 1); + for (j = 0; j < sal_systab->entry_count; j++) { + if (*p == SAL_DESC_ENTRY_POINT) { + ep = (struct ia64_sal_desc_entry_point + *)p; + ia64_sal_handler_init(__va + (ep->sal_proc), + __va(ep->gp)); + return; + } + p += SAL_DESC_SIZE(*p); + } + } + } + /* Uh-oh, SAL not available?? */ + printk(KERN_ERR "failed to find SAL entry point\n"); +} + +/** + * sn_serial_console_early_setup - Sets up early console output support + * + * pulled from drivers/serial/sn_console.c + */ +int __init sn_serial_console_early_setup(void) +{ + if (strcmp("sn2",acpi_get_sysname())) + return -1; + + early_sn_setup(); /* Find SAL entry points */ + serial_register_uart(0, &sn_sal_console, NULL); + + return 0; +} + +/* + * sn_putc - Send a character to the console, polled or interrupt mode + */ +void sn_putc(struct serial_port *port, char c) +{ + return ia64_sn_console_putc(c); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/vcpu.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/vcpu.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,1843 @@ +/* + * Virtualized CPU functions + * + * Copyright (C) 2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <linux/sched.h> +#include <public/arch-ia64.h> +#include <asm/ia64_int.h> +#include <asm/vcpu.h> +#include <asm/regionreg.h> +#include <asm/tlb.h> +#include <asm/processor.h> +#include <asm/delay.h> +#include <asm/vmx_vcpu.h> + +typedef union { + struct ia64_psr ia64_psr; + unsigned long i64; +} PSR; + +//typedef struct pt_regs REGS; +//typedef struct domain VCPU; + +// this def for vcpu_regs won't work if kernel stack is present +#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs) +#define PSCB(x,y) VCPU(x,y) +#define PSCBX(x,y) x->arch.y + +#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 STATIC + +#ifdef PRIVOP_ADDR_COUNT +struct privop_addr_count privop_addr_counter[PRIVOP_COUNT_NINSTS] = { + { "=ifa", { 0 }, { 0 }, 0 }, + { "thash", { 0 }, { 0 }, 0 }, + 0 +}; +extern void privop_count_addr(unsigned long addr, int inst); +#define PRIVOP_COUNT_ADDR(regs,inst) privop_count_addr(regs->cr_iip,inst) +#else +#define PRIVOP_COUNT_ADDR(x,y) do {} while (0) +#endif + +unsigned long dtlb_translate_count = 0; +unsigned long tr_translate_count = 0; +unsigned long phys_translate_count = 0; + +unsigned long vcpu_verbose = 0; +#define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) + +extern TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa); +extern TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa); + +/************************************************************************** + VCPU general register access routines +**************************************************************************/ + +UINT64 +vcpu_get_gr(VCPU *vcpu, unsigned reg) +{ + REGS *regs = vcpu_regs(vcpu); + UINT64 val; + + if (!reg) return 0; + getreg(reg,&val,0,regs); // FIXME: handle NATs later + return 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 reg, UINT64 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 + return IA64_NO_FAULT; +} + +/************************************************************************** + VCPU privileged application register access routines +**************************************************************************/ + +IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val) +{ + 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); + else PSCB(vcpu,krs[reg]) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *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]); + return IA64_NO_FAULT; +} + +/************************************************************************** + VCPU processor status register access routines +**************************************************************************/ + +void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode) +{ + /* only do something if mode changes */ + if (!!newmode ^ !!PSCB(vcpu,metaphysical_mode)) { + if (newmode) set_metaphysical_rr0(); + else if (PSCB(vcpu,rrs[0]) != -1) + set_one_rr(0, PSCB(vcpu,rrs[0])); + PSCB(vcpu,metaphysical_mode) = newmode; + } +} + +IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,TRUE); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) +{ + struct ia64_psr psr, imm, *ipsr; + REGS *regs = vcpu_regs(vcpu); + + //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"); + ipsr = (struct ia64_psr *)®s->cr_ipsr; + imm = *(struct ia64_psr *)&imm24; + // interrupt flag + if (imm.i) PSCB(vcpu,interrupt_delivery_enabled) = 0; + 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 (imm.pp) { ipsr->pp = 0; psr.pp = 0; } + 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; +} + +extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu); +#define SPURIOUS_VECTOR 0xf + +IA64FAULT vcpu_set_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,FALSE); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_psr_i(VCPU *vcpu) +{ + PSCB(vcpu,interrupt_delivery_enabled) = 1; + PSCB(vcpu,interrupt_collection_enabled) = 1; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) +{ + struct ia64_psr psr, imm, *ipsr; + REGS *regs = vcpu_regs(vcpu); + UINT64 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"); + 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; + if (imm.pp) { ipsr->pp = 1; psr.pp = 1; } + if (imm.sp) { ipsr->sp = 1; psr.sp = 1; } + if (imm.i) { + if (!PSCB(vcpu,interrupt_delivery_enabled)) { +//printf("vcpu_set_psr_sm: psr.ic 0->1 "); + enabling_interrupts = 1; + } + PSCB(vcpu,interrupt_delivery_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.be) { + printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n"); + 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 0 // now done with deliver_pending_interrupts + if (enabling_interrupts) { + if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) { +//printf("with interrupts pending\n"); + return IA64_EXTINT_VECTOR; + } +//else printf("but nothing pending\n"); + } +#endif + if (enabling_interrupts && + 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) +{ + struct ia64_psr psr, newpsr, *ipsr; + REGS *regs = vcpu_regs(vcpu); + UINT64 enabling_interrupts = 0; + + // TODO: All of these bits need to be virtualized + __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); + // 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.pp) { ipsr->pp = 1; psr.pp = 1; } + if (newpsr.up) { ipsr->up = 1; psr.up = 1; } + if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; } + if (newpsr.i) { + if (!PSCB(vcpu,interrupt_delivery_enabled)) + enabling_interrupts = 1; + PSCB(vcpu,interrupt_delivery_enabled) = 1; + } + 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); + } + //__asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); +#if 0 // now done with deliver_pending_interrupts + if (enabling_interrupts) { + if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + return IA64_EXTINT_VECTOR; + } +#endif + if (enabling_interrupts && + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu,pending_interruption) = 1; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval) +{ + UINT64 psr; + struct ia64_psr newpsr; + + // TODO: This needs to return a "filtered" view of + // the psr, not the actual psr. Probably the psr needs + // to be a field in regs (in addition to ipsr). + __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); + newpsr = *(struct ia64_psr *)&psr; + if (newpsr.cpl == 2) newpsr.cpl = 0; + if (PSCB(vcpu,interrupt_delivery_enabled)) newpsr.i = 1; + else newpsr.i = 0; + if (PSCB(vcpu,interrupt_collection_enabled)) newpsr.ic = 1; + else newpsr.ic = 0; + *pval = *(unsigned long *)&newpsr; + return IA64_NO_FAULT; +} + +BOOLEAN vcpu_get_psr_ic(VCPU *vcpu) +{ + return !!PSCB(vcpu,interrupt_collection_enabled); +} + +BOOLEAN vcpu_get_psr_i(VCPU *vcpu) +{ + return !!PSCB(vcpu,interrupt_delivery_enabled); +} + +UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) +{ + UINT64 dcr = PSCBX(vcpu,dcr); + PSR psr = {0}; + + //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",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.i = PSCB(vcpu,interrupt_delivery_enabled); + 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...",psr.i64); + return psr.i64; +} + +/************************************************************************** + VCPU control register access routines +**************************************************************************/ + +IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval) +{ +extern unsigned long privop_trace; +//privop_trace=0; +//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); +} + +IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCBX(vcpu,iva) & ~0x7fffL; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,pta); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval) +{ + //REGS *regs = vcpu_regs(vcpu); + //*pval = regs->cr_ipsr; + *pval = PSCB(vcpu,ipsr); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,isr); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval) +{ + //REGS *regs = vcpu_regs(vcpu); + //*pval = regs->cr_iip; + *pval = PSCB(vcpu,iip); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval) +{ + UINT64 val = PSCB(vcpu,ifa); + REGS *regs = vcpu_regs(vcpu); + PRIVOP_COUNT_ADDR(regs,_GET_IFA); + *pval = val; + return (IA64_NO_FAULT); +} + +unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) +{ + ia64_rr rr; + + rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; + return(rr.ps); +} + +unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr) +{ + ia64_rr rr; + + rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; + return(rr.rid); +} + +unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 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); +} + + +IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval) +{ + UINT64 val = PSCB(vcpu,itir); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval) +{ + UINT64 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); +} + +IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *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); +} + +IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval) +{ + UINT64 val = PSCB(vcpu,iim); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval) +{ + //return vcpu_thash(vcpu,PSCB(vcpu,ifa),pval); + UINT64 val = PSCB(vcpu,iha); + REGS *regs = vcpu_regs(vcpu); + PRIVOP_COUNT_ADDR(regs,_THASH); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val) +{ +extern unsigned long privop_trace; +//privop_trace=1; + // 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); +} + +IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val) +{ + PSCBX(vcpu,iva) = val & ~0x7fffL; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val) +{ + if (val & IA64_PTA_LFMT) { + printf("*** No support for VHPT long format yet!!\n"); + 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; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,ipsr) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,isr) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,iip) = val; + return IA64_NO_FAULT; +} + +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); +} + +IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,ifa) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,itir) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 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; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val) +{ + //REGS *regs = vcpu_regs(vcpu); + PSCB(vcpu,ifs) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,iim) = val; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val) +{ + PSCB(vcpu,iha) = val; + return IA64_NO_FAULT; +} + +/************************************************************************** + VCPU interrupt control register access routines +**************************************************************************/ + +void vcpu_pend_unspecified_interrupt(VCPU *vcpu) +{ + PSCB(vcpu,pending_interruption) = 1; +} + +void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) +{ + if (vector & ~0xff) { + printf("vcpu_pend_interrupt: bad vector\n"); + return; + } +#ifdef CONFIG_VTI + if ( VMX_DOMAIN(vcpu) ) { + set_bit(vector,VPD_CR(vcpu,irr)); + } else +#endif // CONFIG_VTI + { + /* if (!test_bit(vector,PSCB(vcpu,delivery_mask))) return; */ + if (test_bit(vector,PSCBX(vcpu,irr))) { +//printf("vcpu_pend_interrupt: overrun\n"); + } + set_bit(vector,PSCBX(vcpu,irr)); + PSCB(vcpu,pending_interruption) = 1; + } + +#if 0 + /* Keir: I think you should unblock when an interrupt is pending. */ + { + int running = test_bit(_VCPUF_running, &vcpu->vcpu_flags); + vcpu_unblock(vcpu); + if ( running ) + smp_send_event_check_cpu(vcpu->processor); + } +#endif +} + +void early_tick(VCPU *vcpu) +{ + UINT64 *p = &PSCBX(vcpu,irr[3]); + printf("vcpu_check_pending: about to deliver early tick\n"); + printf("&irr[0]=%p, irr[0]=0x%lx\n",p,*p); +} + +#define IA64_TPR_MMI 0x10000 +#define IA64_TPR_MIC 0x000f0 + +/* checks to see if a VCPU has any unmasked pending interrupts + * if so, returns the highest, else returns SPURIOUS_VECTOR */ +/* NOTE: Since this gets called from vcpu_get_ivr() and the + * 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) +{ + UINT64 *p, *q, *r, bits, bitnum, mask, i, vector; + + p = &PSCBX(vcpu,irr[3]); + /* q = &PSCB(vcpu,delivery_mask[3]); */ + r = &PSCBX(vcpu,insvc[3]); + for (i = 3; ; p--, q--, r--, i--) { + bits = *p /* & *q */; + 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 + 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...",bitnum); + vector = bitnum+(i*64); + mask = 1L << bitnum; +//printf("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...",vector); + if (*r >= mask) { + // masked by equal inservice +//printf("but masked by equal inservice\n"); + return SPURIOUS_VECTOR; + } + 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) { + //tpr.mic masks class +//printf("but masked by tpr.mic\n"); + return SPURIOUS_VECTOR; + } + +//printf("returned to caller\n"); +#if 0 +if (vector == (PSCB(vcpu,itv) & 0xff)) { + UINT64 now = ia64_get_itc(); + UINT64 itm = PSCBX(vcpu,domain_itm); + if (now < itm) early_tick(vcpu); + +} +#endif + return vector; +} + +UINT64 vcpu_deliverable_interrupts(VCPU *vcpu) +{ + return (vcpu_get_psr_i(vcpu) && + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR); +} + +UINT64 vcpu_deliverable_timer(VCPU *vcpu) +{ + return (vcpu_get_psr_i(vcpu) && + vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu,itv)); +} + +IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval) +{ +extern unsigned long privop_trace; +//privop_trace=1; + //TODO: Implement this + printf("vcpu_get_lid: WARNING: Getting cr.lid always returns zero\n"); + //*pval = 0; + *pval = ia64_getreg(_IA64_REG_CR_LID); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) +{ + int i; + UINT64 vector, mask; + +#define HEARTBEAT_FREQ 16 // period in seconds +#ifdef HEARTBEAT_FREQ +#define N_DOMS 16 // period in seconds + static long count[N_DOMS] = { 0 }; + static long nonclockcount[N_DOMS] = { 0 }; + REGS *regs = vcpu_regs(vcpu); + unsigned domid = vcpu->domain->domain_id; +#endif +#ifdef IRQ_DEBUG + static char firstivr = 1; + static char firsttime[256]; + if (firstivr) { + int i; + 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; + *pval = vector; + return IA64_NO_FAULT; + } +#ifdef HEARTBEAT_FREQ + if (domid >= N_DOMS) domid = N_DOMS-1; + 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(); + } + } + 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=%d,itc=%lx\n", + vector,ia64_get_itc()); + firsttime[vector]=0; + } +#endif + i = vector >> 6; + mask = 1L << (vector & 0x3f); +//printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector); + PSCBX(vcpu,insvc[i]) |= mask; + PSCBX(vcpu,irr[i]) &= ~mask; + //PSCB(vcpu,pending_interruption)--; + *pval = vector; + // if delivering a timer interrupt, remember domain_itm + if (vector == (PSCB(vcpu,itv) & 0xff)) { + PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm); + } + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,tpr); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval) +{ + *pval = 0L; // reads of eoi always return 0 + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval) +{ +#ifndef IRR_USE_FIXED + printk("vcpu_get_irr: called, not implemented yet\n"); + return IA64_ILLOP_FAULT; +#else + *pval = vcpu->irr[0]; + return (IA64_NO_FAULT); +#endif +} + +IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval) +{ +#ifndef IRR_USE_FIXED + printk("vcpu_get_irr: called, not implemented yet\n"); + return IA64_ILLOP_FAULT; +#else + *pval = vcpu->irr[1]; + return (IA64_NO_FAULT); +#endif +} + +IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval) +{ +#ifndef IRR_USE_FIXED + printk("vcpu_get_irr: called, not implemented yet\n"); + return IA64_ILLOP_FAULT; +#else + *pval = vcpu->irr[2]; + return (IA64_NO_FAULT); +#endif +} + +IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval) +{ +#ifndef IRR_USE_FIXED + printk("vcpu_get_irr: called, not implemented yet\n"); + return IA64_ILLOP_FAULT; +#else + *pval = vcpu->irr[3]; + return (IA64_NO_FAULT); +#endif +} + +IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,itv); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,pmv); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval) +{ + *pval = PSCB(vcpu,cmcv); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *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); +} + +IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *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); +} + +IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val) +{ + printf("vcpu_set_lid: Setting cr.lid is unsupported\n"); + return (IA64_ILLOP_FAULT); +} + +IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val) +{ + if (val & 0xff00) return IA64_RSVDREG_FAULT; + PSCB(vcpu,tpr) = val; + if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu,pending_interruption) = 1; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val) +{ + UINT64 *p, bits, vec, bitnum; + int i; + + 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.\r\n"); + return; + } + bitnum = ia64_fls(bits); + vec = bitnum + (i*64); + /* clear the correct bit */ + bits &= ~(1L << bitnum); + *p = bits; + /* clearing an eoi bit may unmask another pending interrupt... */ + if (PSCB(vcpu,interrupt_delivery_enabled)) { // but only if enabled... + // worry about this later... Linux only calls eoi + // with interrupts disabled + printf("Trying to EOI interrupt with interrupts enabled\r\n"); + } + if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu,pending_interruption) = 1; +//printf("YYYYY vcpu_set_eoi: Successful\n"); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val) +{ + if (!(val & (1L << 16))) { + printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); + return (IA64_ILLOP_FAULT); + } + // no place to save this state but nothing to do anyway + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val) +{ + if (!(val & (1L << 16))) { + printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); + return (IA64_ILLOP_FAULT); + } + // no place to save this state but nothing to do anyway + return (IA64_NO_FAULT); +} + +// parameter is a time interval specified in cycles +void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles) +{ + PSCBX(vcpu,xen_timer_interval) = cycles; + vcpu_set_next_timer(vcpu); + printf("vcpu_enable_timer(%d): interval set to %d cycles\n", + PSCBX(vcpu,xen_timer_interval)); + __set_bit(PSCB(vcpu,itv), PSCB(vcpu,delivery_mask)); +} + +IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val) +{ +extern unsigned long privop_trace; +//privop_trace=1; + if (val & 0xef00) return (IA64_ILLOP_FAULT); + PSCB(vcpu,itv) = val; + if (val & 0x10000) { +printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCBX(vcpu,domain_itm)); + PSCBX(vcpu,domain_itm) = 0; + } + else vcpu_enable_timer(vcpu,1000000L); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val) +{ + 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) +{ + 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) +{ + if (index > 7) return 0; + return PSCB(vcpu,tmp[index]); +} + +void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val) +{ + if (index <= 7) PSCB(vcpu,tmp[index]) = val; +} + +/************************************************************************** +Interval timer routines +**************************************************************************/ + +BOOLEAN vcpu_timer_disabled(VCPU *vcpu) +{ + UINT64 itv = PSCB(vcpu,itv); + return(!itv || !!(itv & 0x10000)); +} + +BOOLEAN vcpu_timer_inservice(VCPU *vcpu) +{ + UINT64 itv = PSCB(vcpu,itv); + return (test_bit(itv, PSCBX(vcpu,insvc))); +} + +BOOLEAN vcpu_timer_expired(VCPU *vcpu) +{ + 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; + return TRUE; +} + +void vcpu_safe_set_itm(unsigned long val) +{ + unsigned long epsilon = 100; + UINT64 now = ia64_get_itc(); + + local_irq_disable(); + 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; + val = now + epsilon; + epsilon <<= 1; + } + local_irq_enable(); +} + +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(); + //UINT64 interval = PSCBX(vcpu,xen_timer_interval); + + /* gloss over the wraparound problem for now... we know it exists + * but it doesn't matter right now */ + +#if 0 + /* ensure at least next SP tick is in the future */ + if (!interval) PSCBX(vcpu,xen_itm) = now + +#if 0 + (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE : + DEFAULT_CLOCK_RATE); +#else + 3000000; +//printf("vcpu_set_next_timer: HACK!\n"); +#endif +#if 0 + if (PSCBX(vcpu,xen_itm) < now) + while (PSCBX(vcpu,xen_itm) < now + (interval>>1)) + PSCBX(vcpu,xen_itm) += interval; +#endif +#endif + + if (is_idle_task(vcpu->domain)) { + printf("****** vcpu_set_next_timer called during idle!!\n"); + } + //s = PSCBX(vcpu,xen_itm); + if (d && (d > now) && (d < s)) { + vcpu_safe_set_itm(d); + //using_domain_as_itm++; + } + else { + vcpu_safe_set_itm(s); + //using_xen_as_itm++; + } +} + +IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 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; + vcpu_set_next_timer(vcpu); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) +{ + + UINT64 oldnow = ia64_get_itc(); + UINT64 olditm = PSCBX(vcpu,domain_itm); + unsigned long d = olditm - oldnow; + unsigned long x = local_cpu_data->itm_next - oldnow; + + UINT64 newnow = val, min_delta; + +#define DISALLOW_SETTING_ITC_FOR_NOW +#ifdef DISALLOW_SETTING_ITC_FOR_NOW +printf("vcpu_set_itc: Setting ar.itc is currently disabled\n"); +#else + local_irq_disable(); + if (olditm) { +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); + 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 { + vcpu_safe_set_itm(x); + //using_xen_as_itm++; + } + local_irq_enable(); +#endif + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval) +{ + //FIXME: Implement this + printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n"); + return (IA64_NO_FAULT); + //return (IA64_ILLOP_FAULT); +} + +IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval) +{ + //TODO: Implement this + printf("vcpu_get_itc: Getting ar.itc is unsupported\n"); + return (IA64_ILLOP_FAULT); +} + +void vcpu_pend_timer(VCPU *vcpu) +{ + UINT64 itv = PSCB(vcpu,itv) & 0xff; + + if (vcpu_timer_disabled(vcpu)) return; + //if (vcpu_timer_inservice(vcpu)) return; + if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) { + // already delivered an interrupt for this so + // don't deliver another + return; + } +#if 0 + // attempt to flag "timer tick before its due" source + { + UINT64 itm = PSCBX(vcpu,domain_itm); + UINT64 now = ia64_get_itc(); + if (now < itm) printf("******* vcpu_pend_timer: pending before due!\n"); + } +#endif + vcpu_pend_interrupt(vcpu, itv); +} + +// returns true if ready to deliver a timer interrupt too early +UINT64 vcpu_timer_pending_early(VCPU *vcpu) +{ + UINT64 now = ia64_get_itc(); + UINT64 itm = PSCBX(vcpu,domain_itm); + + if (vcpu_timer_disabled(vcpu)) return 0; + if (!itm) return 0; + return (vcpu_deliverable_timer(vcpu) && (now < itm)); +} + +//FIXME: This is a hack because everything dies if a timer tick is lost +void vcpu_poke_timer(VCPU *vcpu) +{ + UINT64 itv = PSCB(vcpu,itv) & 0xff; + UINT64 now = ia64_get_itc(); + UINT64 itm = PSCBX(vcpu,domain_itm); + UINT64 irr; + + if (vcpu_timer_disabled(vcpu)) return; + if (!itm) return; + if (itv != 0xefL) { + printf("vcpu_poke_timer: unimplemented itv=%lx!\n",itv); + while(1); + } + // using 0xef instead of itv so can get real irr + if (now > itm && !test_bit(0xefL, PSCBX(vcpu,insvc))) { + if (!test_bit(0xefL,PSCBX(vcpu,irr))) { + irr = ia64_getreg(_IA64_REG_CR_IRR3); + if (irr & (1L<<(0xef-0xc0))) return; +if (now-itm>0x800000) +printf("*** poking timer: now=%lx,vitm=%lx,xitm=%lx,itm=%lx\n",now,itm,local_cpu_data->itm_next,ia64_get_itm()); + vcpu_pend_timer(vcpu); + } + } +} + + +/************************************************************************** +Privileged operation emulation routines +**************************************************************************/ + +IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa) +{ + PSCB(vcpu,tmp[0]) = ifa; // save ifa in vcpu structure, then specify IA64_FORCED_IFA + return (vcpu_get_rr_ve(vcpu,ifa) ? IA64_DATA_TLB_VECTOR : IA64_ALT_DATA_TLB_VECTOR) | IA64_FORCED_IFA; +} + + +IA64FAULT vcpu_rfi(VCPU *vcpu) +{ + // TODO: Only allowed for current vcpu + PSR psr; + UINT64 int_enable, regspsr = 0; + UINT64 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; + if (psr.ia64_psr.i) PSCB(vcpu,interrupt_delivery_enabled) = 1; + 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; + 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); + } + 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; + // 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 { + regs->cr_ipsr = psr.i64; + regs->cr_iip = PSCB(vcpu,iip); + } + PSCB(vcpu,interrupt_collection_enabled) = 1; + vcpu_bsw1(vcpu); + PSCB(vcpu,interrupt_delivery_enabled) = int_enable; + return (IA64_NO_FAULT); +} + +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; + } + 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 = RR_TO_PS(get_rr(vadr)); + 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; + +#if 0 + if (VHPT_addr1 == 0xe000000000000000L) { + printf("vcpu_thash: thash unsupported with rr7 @%lx\n", + PSCB(vcpu,iip)); + return (IA64_ILLOP_FAULT); + } +#endif +//verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr); + *pval = VHPT_addr; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +{ + printf("vcpu_ttag: ttag instruction unsupported\n"); + return (IA64_ILLOP_FAULT); +} + +#define itir_ps(itir) ((itir >> 2) & 0x3f) +#define itir_mask(itir) (~((1UL << itir_ps(itir)) - 1)) + +unsigned long vhpt_translate_count = 0; + +IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir) +{ + unsigned long pta, pta_mask, iha, pte, ps; + TR_ENTRY *trp; + ia64_rr rr; + + if (!(address >> 61)) { + if (!PSCB(vcpu,metaphysical_mode)) { + REGS *regs = vcpu_regs(vcpu); + 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 %p, viip=%p, vipsr=%p, iip=%p, ipsr=%p continuing\n", address, viip, vipsr, iip, ipsr); + } + + *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX; + *itir = PAGE_SHIFT << 2; + phys_translate_count++; + return IA64_NO_FAULT; + } + + /* check translation registers */ + if ((trp = match_tr(vcpu,address))) { + tr_translate_count++; + *pteval = trp->page_flags; + *itir = trp->itir; + return IA64_NO_FAULT; + } + + /* check 1-entry TLB */ + if ((trp = match_dtlb(vcpu,address))) { + dtlb_translate_count++; + *pteval = trp->page_flags; + *itir = trp->itir; + return IA64_NO_FAULT; + } + + /* check guest VHPT */ + pta = PSCB(vcpu,pta); + rr.rrval = PSCB(vcpu,rrs)[address>>61]; + if (rr.ve && (pta & IA64_PTA_VE)) + { + if (pta & IA64_PTA_VF) + { + /* long format VHPT - not implemented */ + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + } + else + { + /* short format VHPT */ + + /* avoid recursively walking VHPT */ + pta_mask = (itir_mask(pta) << 3) >> 3; + if (((address ^ pta) & pta_mask) == 0) + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + + vcpu_thash(vcpu, address, &iha); + if (__copy_from_user(&pte, (void *)iha, sizeof(pte)) != 0) + return IA64_VHPT_TRANS_VECTOR; + + /* + * 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 & _PAGE_P) + { + *pteval = pte; + *itir = vcpu_get_itir_on_fault(vcpu,address); + vhpt_translate_count++; + return IA64_NO_FAULT; + } + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + } + } + return (is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR); +} + +IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +{ + UINT64 pteval, itir, mask; + IA64FAULT fault; + + fault = vcpu_translate(vcpu, vadr, 1, &pteval, &itir); + if (fault == IA64_NO_FAULT) + { + mask = itir_mask(itir); + *padr = (pteval & _PAGE_PPN_MASK & mask) | (vadr & ~mask); + return (IA64_NO_FAULT); + } + else + { + PSCB(vcpu,tmp[0]) = vadr; // save ifa in vcpu structure, then specify IA64_FORCED_IFA + return (fault | IA64_FORCED_IFA); + } +} + +IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) +{ + printf("vcpu_tak: tak instruction unsupported\n"); + return (IA64_ILLOP_FAULT); + // HACK ALERT: tak does a thash for now + //return vcpu_thash(vcpu,vadr,key); +} + +/************************************************************************** + VCPU debug breakpoint register access routines +**************************************************************************/ + +IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 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); +} + +IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 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); +} + +IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + // TODO: unimplemented DBRs return a reserved register fault + UINT64 val = ia64_get_dbr(reg); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + // TODO: unimplemented IBRs return a reserved register fault + UINT64 val = ia64_get_ibr(reg); + *pval = val; + return (IA64_NO_FAULT); +} + +/************************************************************************** + VCPU performance monitor register access routines +**************************************************************************/ + +IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 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); +} + +IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 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); +} + +IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + // NOTE: Reads from unimplemented PMC registers return zero + UINT64 val = (UINT64)ia64_get_pmc(reg); + *pval = val; + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + // NOTE: Reads from unimplemented PMD registers return zero + UINT64 val = (UINT64)ia64_get_pmd(reg); + *pval = val; + return (IA64_NO_FAULT); +} + +/************************************************************************** + VCPU banked general register access routines +**************************************************************************/ + +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]); + int i; + + if (PSCB(vcpu,banknum)) { + for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; } + PSCB(vcpu,banknum) = 0; + } + return (IA64_NO_FAULT); +} + +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]); + int i; + + if (!PSCB(vcpu,banknum)) { + for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; } + PSCB(vcpu,banknum) = 1; + } + return (IA64_NO_FAULT); +} + +/************************************************************************** + VCPU cpuid access routines +**************************************************************************/ + + +IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *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); + break; + case 1: + *pval = 0; + break; + case 2: + *pval = 0; + break; + case 3: + *pval = ia64_get_cpuid(3); + break; + case 4: + *pval = ia64_get_cpuid(4); + break; + default: + if (reg > (ia64_get_cpuid(3) & 0xff)) + return IA64_RSVDREG_FAULT; + *pval = ia64_get_cpuid(reg); + break; + } + return (IA64_NO_FAULT); +} + +/************************************************************************** + VCPU region register access routines +**************************************************************************/ + +unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) +{ + ia64_rr rr; + + rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; + return(rr.ve); +} + +IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) +{ + PSCB(vcpu,rrs)[reg>>61] = val; + // warning: set_one_rr() does it "live" + set_one_rr(reg,val); + return (IA64_NO_FAULT); +} + +IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +{ + UINT val = PSCB(vcpu,rrs)[reg>>61]; + *pval = val; + return (IA64_NO_FAULT); +} + +/************************************************************************** + VCPU protection key register access routines +**************************************************************************/ + +IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *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); + *pval = val; + return (IA64_NO_FAULT); +#endif +} + +IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 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); + vcpu->pkrs[reg] = val; + ia64_set_pkr(reg,val); + return (IA64_NO_FAULT); +#endif +} + +/************************************************************************** + VCPU translation register access routines +**************************************************************************/ + +static void vcpu_purge_tr_entry(TR_ENTRY *trp) +{ + trp->p = 0; +} + +static void vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + UINT64 ps; + + trp->itir = itir; + trp->rid = virtualize_rid(current, get_rr(ifa) & RR_RID_MASK); + trp->p = 1; + ps = trp->ps; + trp->page_flags = pte; + if (trp->pl < 2) trp->pl = 2; + trp->vadr = ifa & ~0xfff; + if (ps > 12) { // "ignore" relevant low-order bits + trp->ppn &= ~((1UL<<(ps-12))-1); + trp->vadr &= ~((1UL<<ps)-1); + } +} + +TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count) +{ + unsigned long rid = (get_rr(ifa) & RR_RID_MASK); + int i; + + for (i = 0; i < count; i++, trp++) { + if (!trp->p) continue; + if (physicalize_rid(vcpu,trp->rid) != rid) continue; + if (ifa < trp->vadr) continue; + if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; + //if (trp->key && !match_pkr(vcpu,trp->key)) continue; + return trp; + } + return 0; +} + +TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa) +{ + TR_ENTRY *trp; + + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.dtrs,ifa,NDTRS); + if (trp) return trp; + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.itrs,ifa,NITRS); + if (trp) return trp; + return 0; +} + +IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, + UINT64 itir, UINT64 ifa) +{ + TR_ENTRY *trp; + + if (slot >= NDTRS) return IA64_RSVDREG_FAULT; + trp = &PSCBX(vcpu,dtrs[slot]); +//printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa); + vcpu_set_tr_entry(trp,pte,itir,ifa); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, + UINT64 itir, UINT64 ifa) +{ + TR_ENTRY *trp; + + if (slot >= NITRS) return IA64_RSVDREG_FAULT; + trp = &PSCBX(vcpu,itrs[slot]); +//printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa); + vcpu_set_tr_entry(trp,pte,itir,ifa); + return IA64_NO_FAULT; +} + +/************************************************************************** + VCPU translation cache access routines +**************************************************************************/ + +void foobar(void) { /*vcpu_verbose = 1;*/ } + +extern struct domain *dom0; + +void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 mp_pte, UINT64 logps) +{ + unsigned long psr; + unsigned long ps = (vcpu->domain==dom0) ? logps : PAGE_SHIFT; + + // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK! + // FIXME, must be inlined or potential for nested fault here! + if ((vcpu->domain==dom0) && (logps < PAGE_SHIFT)) { + printf("vcpu_itc_no_srlz: domain0 use of smaller page size!\n"); + //FIXME: kill domain here + while(1); + } + psr = ia64_clear_ic(); + 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)) { + // 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); + } + // 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); +#endif + if (IorD & 0x4) return; // don't place in 1-entry TLB + if (IorD & 0x1) { + vcpu_set_tr_entry(&PSCBX(vcpu,itlb),pte,ps<<2,vaddr); + PSCBX(vcpu,itlb_pte) = mp_pte; + } + if (IorD & 0x2) { + vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),pte,ps<<2,vaddr); + PSCBX(vcpu,dtlb_pte) = mp_pte; + } +} + +// NOTE: returns a physical pte, NOT a "metaphysical" pte, so do not check +// the physical address contained for correctness +TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa) +{ + TR_ENTRY *trp; + + if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) + return (&vcpu->arch.dtlb); + return 0UL; +} + +IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + unsigned long pteval, logps = (itir >> 2) & 0x3f; + unsigned long translate_domain_pte(UINT64,UINT64,UINT64); + + if (logps < PAGE_SHIFT) { + printf("vcpu_itc_d: domain trying to use smaller page size!\n"); + //FIXME: kill domain here + while(1); + } + //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize + pteval = translate_domain_pte(pte,ifa,itir); + if (!pteval) return IA64_ILLOP_FAULT; + vcpu_itc_no_srlz(vcpu,2,ifa,pteval,pte,logps); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + unsigned long pteval, logps = (itir >> 2) & 0x3f; + unsigned long translate_domain_pte(UINT64,UINT64,UINT64); + + // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK! + if (logps < PAGE_SHIFT) { + printf("vcpu_itc_i: domain trying to use smaller page size!\n"); + //FIXME: kill domain here + while(1); + } + //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize + pteval = translate_domain_pte(pte,ifa,itir); + // FIXME: what to do if bad physical address? (machine check?) + if (!pteval) return IA64_ILLOP_FAULT; + vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,pte,logps); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 addr_range) +{ + printk("vcpu_ptc_l: called, not implemented yet\n"); + return IA64_ILLOP_FAULT; +} + +// At privlvl=0, fc performs no access rights or protection key checks, while +// at privlvl!=0, fc performs access rights checks as if it were a 1-byte +// read but no protection key check. Thus in order to avoid an unexpected +// 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) +{ + // TODO: Only allowed for current vcpu + UINT64 mpaddr, paddr; + IA64FAULT fault; + unsigned long translate_domain_mpaddr(unsigned long); + IA64FAULT vcpu_tpa(VCPU *, UINT64, UINT64 *); + + fault = vcpu_tpa(vcpu, vadr, &mpaddr); + if (fault == IA64_NO_FAULT) { + paddr = translate_domain_mpaddr(mpaddr); + ia64_fc(__va(paddr)); + } + return fault; +} + +int ptce_count = 0; +IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) +{ + // Note that this only needs to be called once, i.e. the + // architected loop to purge the entire TLB, should use + // base = stride1 = stride2 = 0, count0 = count 1 = 1 + +#ifdef VHPT_GLOBAL + vhpt_flush(); // FIXME: This is overdoing it +#endif + local_flush_tlb_all(); + // just invalidate the "whole" tlb + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 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) +{ + extern ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits); + // 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); +#ifdef VHPT_GLOBAL + vhpt_flush_address(vadr,addr_range); +#endif + ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT); + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) +{ + printf("vcpu_ptr_d: Purging TLB is unsupported\n"); + return (IA64_ILLOP_FAULT); +} + +IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) +{ + printf("vcpu_ptr_i: Purging TLB is unsupported\n"); + return (IA64_ILLOP_FAULT); +} + +void vcpu_set_regs(VCPU *vcpu, REGS *regs) +{ + vcpu->arch.regs = regs; +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/vhpt.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/vhpt.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,151 @@ +/* + * Initialize VHPT support. + * + * Copyright (C) 2004 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/pgalloc.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/vhpt.h> + +unsigned long vhpt_paddr, vhpt_pend, vhpt_pte; + +void vhpt_flush(void) +{ + struct vhpt_lf_entry *v = (void *)VHPT_ADDR; + int i, cnt = 0; +#if 0 +static int firsttime = 2; + +if (firsttime) firsttime--; +else { +printf("vhpt_flush: *********************************************\n"); +printf("vhpt_flush: *********************************************\n"); +printf("vhpt_flush: *********************************************\n"); +printf("vhpt_flush: flushing vhpt (seems to crash at rid wrap?)...\n"); +printf("vhpt_flush: *********************************************\n"); +printf("vhpt_flush: *********************************************\n"); +printf("vhpt_flush: *********************************************\n"); +} +#endif + for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) { + v->itir = 0; + v->CChain = 0; + v->page_flags = 0; + v->ti_tag = INVALID_TI_TAG; + } + // initialize cache too??? +} + +#ifdef VHPT_GLOBAL +void vhpt_flush_address(unsigned long vadr, unsigned long addr_range) +{ + unsigned long ps; + struct vhpt_lf_entry *vlfe; + + if ((vadr >> 61) == 7) { + // no vhpt for region 7 yet, see vcpu_itc_no_srlz + printf("vhpt_flush_address: region 7, spinning...\n"); + while(1); + } +#if 0 + // this only seems to occur at shutdown, but it does occur + if ((!addr_range) || addr_range & (addr_range - 1)) { + printf("vhpt_flush_address: weird range, spinning...\n"); + while(1); + } +//printf("************** vhpt_flush_address(%p,%p)\n",vadr,addr_range); +#endif + while ((long)addr_range > 0) { + vlfe = (struct vhpt_lf_entry *)ia64_thash(vadr); + // FIXME: for now, just blow it away even if it belongs to + // another domain. Later, use ttag to check for match +//if (!(vlfe->ti_tag & INVALID_TI_TAG)) { +//printf("vhpt_flush_address: blowing away valid tag for vadr=%p\n",vadr); +//} + vlfe->ti_tag |= INVALID_TI_TAG; + addr_range -= PAGE_SIZE; + vadr += PAGE_SIZE; + } +} +#endif + +void vhpt_map(void) +{ + unsigned long psr; + + psr = ia64_clear_ic(); + ia64_itr(0x2, IA64_TR_VHPT, VHPT_ADDR, vhpt_pte, VHPT_SIZE_LOG2); + ia64_set_psr(psr); + ia64_srlz_i(); +} + +void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long logps) +{ + unsigned long mask = (1L << logps) - 1; + extern long running_on_sim; + int i; + + if (logps-PAGE_SHIFT > 10 && !running_on_sim) { + // if this happens, we may want to revisit this algorithm + printf("vhpt_multiple_insert:logps-PAGE_SHIFT>10,spinning..\n"); + while(1); + } + if (logps-PAGE_SHIFT > 2) { + // FIXME: Should add counter here to see how often this + // happens (e.g. for 16MB pages!) and determine if it + // is a performance problem. On a quick look, it takes + // about 39000 instrs for a 16MB page and it seems to occur + // only a few times/second, so OK for now. + // An alternate solution would be to just insert the one + // 16KB in the vhpt (but with the full mapping)? + //printf("vhpt_multiple_insert: logps-PAGE_SHIFT==%d," + //"va=%p, pa=%p, pa-masked=%p\n", + //logps-PAGE_SHIFT,vaddr,pte&_PFN_MASK, + //(pte&_PFN_MASK)&~mask); + } + vaddr &= ~mask; + pte = ((pte & _PFN_MASK) & ~mask) | (pte & ~_PFN_MASK); + for (i = 1L << (logps-PAGE_SHIFT); i > 0; i--) { + vhpt_insert(vaddr,pte,logps<<2); + vaddr += PAGE_SIZE; + } +} + +void vhpt_init(void) +{ + unsigned long vhpt_total_size, vhpt_alignment, vhpt_imva; +#if !VHPT_ENABLED + return; +#endif + // allocate a huge chunk of physical memory.... how??? + vhpt_total_size = 1 << VHPT_SIZE_LOG2; // 4MB, 16MB, 64MB, or 256MB + vhpt_alignment = 1 << VHPT_SIZE_LOG2; // 4MB, 16MB, 64MB, or 256MB + printf("vhpt_init: vhpt size=%p, align=%p\n",vhpt_total_size,vhpt_alignment); + /* This allocation only holds true if vhpt table is unique for + * all domains. Or else later new vhpt table should be allocated + * from domain heap when each domain is created. Assume xen buddy + * allocator can provide natural aligned page by order? + */ + vhpt_imva = alloc_xenheap_pages(VHPT_SIZE_LOG2 - PAGE_SHIFT); + if (!vhpt_imva) { + printf("vhpt_init: can't allocate VHPT!\n"); + while(1); + } + vhpt_paddr = __pa(vhpt_imva); + vhpt_pend = vhpt_paddr + vhpt_total_size - 1; + printf("vhpt_init: vhpt paddr=%p, end=%p\n",vhpt_paddr,vhpt_pend); + vhpt_pte = pte_val(pfn_pte(vhpt_paddr >> PAGE_SHIFT, PAGE_KERNEL)); + vhpt_map(); + ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | + VHPT_ENABLED); + vhpt_flush(); +} + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xen.lds.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xen.lds.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,251 @@ +#include <linux/config.h> + +#include <asm/cache.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/pgtable.h> + +#define LOAD_OFFSET (KERNEL_START - KERNEL_TR_PAGE_SIZE) +#include <asm-generic/vmlinux.lds.h> + +OUTPUT_FORMAT("elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(phys_start) +jiffies = jiffies_64; +PHDRS { + code PT_LOAD; + percpu PT_LOAD; + data PT_LOAD; +} +SECTIONS +{ + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + *(.IA_64.unwind.exit.text) + *(.IA_64.unwind_info.exit.text) + } + + v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ + phys_start = _start - LOAD_OFFSET; + + code : { } :code + . = KERNEL_START; + + _text = .; + _stext = .; + + .text : AT(ADDR(.text) - LOAD_OFFSET) + { + *(.text.ivt) + *(.text) + SCHED_TEXT + LOCK_TEXT + *(.gnu.linkonce.t*) + } + .text2 : AT(ADDR(.text2) - LOAD_OFFSET) + { *(.text2) } +#ifdef CONFIG_SMP + .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) + { *(.text.lock) } +#endif + _etext = .; + + /* Read-only data */ + + /* Exception table */ + . = ALIGN(16); + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) + { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) + { + __start___vtop_patchlist = .; + *(.data.patch.vtop) + __end___vtop_patchlist = .; + } + + .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) + { + __start___mckinley_e9_bundles = .; + *(.data.patch.mckinley_e9) + __end___mckinley_e9_bundles = .; + } + + /* Global data */ + _data = .; + +#if defined(CONFIG_IA64_GENERIC) + /* Machine Vector */ + . = ALIGN(16); + .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) + { + machvec_start = .; + *(.machvec) + machvec_end = .; + } +#endif + + /* Unwind info & table: */ + . = ALIGN(8); + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) + { *(.IA_64.unwind_info*) } + .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) + { + __start_unwind = .; + *(.IA_64.unwind*) + __end_unwind = .; + } + + RODATA + + .opd : AT(ADDR(.opd) - LOAD_OFFSET) + { *(.opd) } + + /* Initialization code and data: */ + + . = ALIGN(PAGE_SIZE); + __init_begin = .; + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) + { + _sinittext = .; + *(.init.text) + _einittext = .; + } + + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) + { *(.init.data) } + + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) + { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } + + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) + { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) + { + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + } + __con_initcall_start = .; + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) + { *(.con_initcall.init) } + __con_initcall_end = .; + __security_initcall_start = .; + .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) + { *(.security_initcall.init) } + __security_initcall_end = .; + . = ALIGN(PAGE_SIZE); + __init_end = .; + + /* The initial task and kernel stack */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) + { *(.data.init_task) } + + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) + { *(__special_page_section) + __start_gate_section = .; + *(.data.gate) + __stop_gate_section = .; + } + . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */ + + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) + { *(.data.cacheline_aligned) } + + /* Per-cpu data: */ + percpu : { } :percpu + . = ALIGN(PERCPU_PAGE_SIZE); + __phys_per_cpu_start = .; + .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET) + { + __per_cpu_start = .; + *(.data.percpu) + __per_cpu_end = .; + } + . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */ + + data : { } :data + .data : AT(ADDR(.data) - LOAD_OFFSET) + { *(.data) *(.data1) *(.gnu.linkonce.d*) CONSTRUCTORS } + + . = ALIGN(16); /* gp must be 16-byte aligned for exc. table */ + .got : AT(ADDR(.got) - LOAD_OFFSET) + { *(.got.plt) *(.got) } + __gp = ADDR(.got) + 0x200000; + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) + { *(.sdata) *(.sdata1) *(.srdata) } + _edata = .; + _bss = .; + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) + { *(.sbss) *(.scommon) } + .bss : AT(ADDR(.bss) - LOAD_OFFSET) + { *(.bss) *(COMMON) } + + _end = .; + + code : { } :code + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /* Discard them for now since Intel SoftSDV cannot handle them. + .comment 0 : { *(.comment) } + .note 0 : { *(.note) } + */ + /DISCARD/ : { *(.comment) } + /DISCARD/ : { *(.note) } +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xenasm.S --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xenasm.S Thu Sep 1 18:46:28 2005 @@ -0,0 +1,501 @@ +/* + * Assembly support routines for Xen/ia64 + * + * Copyright (C) 2004 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ + +#include <linux/config.h> +#include <asm/asmmacro.h> +#include <asm/processor.h> +#include <asm/pgtable.h> +#include <asm/vhpt.h> + +#if 0 +// FIXME: there's gotta be a better way... +// ski and spaski are different... moved to xenmisc.c +#define RunningOnHpSki(rx,ry,pn) \ + addl rx = 2, r0; \ + addl ry = 3, r0; \ + ;; \ + mov rx = cpuid[rx]; \ + mov ry = cpuid[ry]; \ + ;; \ + cmp.eq pn,p0 = 0, rx; \ + ;; \ + (pn) movl rx = 0x7000004 ; \ + ;; \ + (pn) cmp.ge pn,p0 = ry, rx; \ + ;; + +//int platform_is_hp_ski(void) +GLOBAL_ENTRY(platform_is_hp_ski) + mov r8 = 0 + RunningOnHpSki(r3,r9,p8) +(p8) mov r8 = 1 + br.ret.sptk.many b0 +END(platform_is_hp_ski) +#endif + +// Change rr7 to the passed value while ensuring +// Xen is mapped into the new region. +// in0: new rr7 value +// in1: Xen virtual address of shared info (to be pinned) +#define PSR_BITS_TO_CLEAR \ + (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ + IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ + IA64_PSR_DFL | IA64_PSR_DFH) +// FIXME? Note that this turns off the DB bit (debug) +#define PSR_BITS_TO_SET IA64_PSR_BN + +//extern void ia64_new_rr7(unsigned long rid,void *shared_info, void *shared_arch_info); +GLOBAL_ENTRY(ia64_new_rr7) + // not sure this unwind statement is correct... + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1) + alloc loc1 = ar.pfs, 3, 8, 0, 0 +1: { + mov r28 = in0 // copy procedure index + mov r8 = ip // save ip to compute branch + mov loc0 = rp // save rp + };; + .body + movl loc2=PERCPU_ADDR + ;; + tpa loc2=loc2 // grab this BEFORE changing rr7 + ;; +#if VHPT_ENABLED + movl loc6=VHPT_ADDR + ;; + tpa loc6=loc6 // grab this BEFORE changing rr7 + ;; +#endif + mov loc5=in1 + ;; + tpa loc5=loc5 // grab this BEFORE changing rr7 + ;; + mov loc7=in2 // arch_vcpu_info_t + ;; + tpa loc7=loc7 // grab this BEFORE changing rr7 + ;; + mov loc3 = psr // save psr + adds r8 = 1f-1b,r8 // calculate return address for call + ;; + tpa r8=r8 // convert rp to physical + ;; + mov loc4=ar.rsc // save RSE configuration + ;; + mov ar.rsc=0 // put RSE in enforced lazy, LE mode + movl r16=PSR_BITS_TO_CLEAR + movl r17=PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 // add in psr the bits to set + ;; + andcm r16=loc3,r16 // removes bits to clear from psr + br.call.sptk.many rp=ia64_switch_mode_phys +1: + // now in physical mode with psr.i/ic off so do rr7 switch + dep r16=-1,r0,61,3 + ;; + mov rr[r16]=in0 + srlz.d + ;; + + // re-pin mappings for kernel text and data + mov r18=KERNEL_TR_PAGE_SHIFT<<2 + movl r17=KERNEL_START + ;; + rsm psr.i | psr.ic + ;; + srlz.i + ;; + ptr.i r17,r18 + ptr.d r17,r18 + ;; + mov cr.itir=r18 + mov cr.ifa=r17 + mov r16=IA64_TR_KERNEL + //mov r3=ip + movl r18=PAGE_KERNEL + ;; + dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT + ;; + or r18=r2,r18 + ;; + srlz.i + ;; + itr.i itr[r16]=r18 + ;; + itr.d dtr[r16]=r18 + ;; + + // re-pin mappings for stack (current), per-cpu, vhpt, and shared info + + // unless overlaps with KERNEL_TR + dep r18=0,r13,0,KERNEL_TR_PAGE_SHIFT + ;; + cmp.eq p7,p0=r17,r18 +(p7) br.cond.sptk .stack_overlaps + ;; + movl r25=PAGE_KERNEL + dep r21=0,r13,60,4 // physical address of "current" + ;; + or r23=r25,r21 // construct PA | page properties + mov r25=IA64_GRANULE_SHIFT<<2 + ;; + ptr.d r13,r25 + ;; + mov cr.itir=r25 + mov cr.ifa=r13 // VA of next task... + ;; + mov r25=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r25]=r23 // wire in new mapping... + ;; +.stack_overlaps: + + movl r22=PERCPU_ADDR + ;; + movl r25=PAGE_KERNEL + ;; + mov r21=loc2 // saved percpu physical address + ;; + or r23=r25,r21 // construct PA | page properties + mov r24=PERCPU_PAGE_SHIFT<<2 + ;; + ptr.d r22,r24 + ;; + mov cr.itir=r24 + mov cr.ifa=r22 + ;; + mov r25=IA64_TR_PERCPU_DATA + ;; + itr.d dtr[r25]=r23 // wire in new mapping... + ;; + +#if VHPT_ENABLED + movl r22=VHPT_ADDR + ;; + movl r25=PAGE_KERNEL + ;; + mov r21=loc6 // saved vhpt physical address + ;; + or r23=r25,r21 // construct PA | page properties + mov r24=VHPT_PAGE_SHIFT<<2 + ;; + ptr.d r22,r24 + ;; + mov cr.itir=r24 + mov cr.ifa=r22 + ;; + mov r25=IA64_TR_VHPT + ;; + itr.d dtr[r25]=r23 // wire in new mapping... + ;; +#endif + + movl r22=SHAREDINFO_ADDR + ;; + movl r25=__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RW) + ;; + mov r21=loc5 // saved sharedinfo physical address + ;; + or r23=r25,r21 // construct PA | page properties + mov r24=PAGE_SHIFT<<2 + ;; + ptr.d r22,r24 + ;; + mov cr.itir=r24 + mov cr.ifa=r22 + ;; + mov r25=IA64_TR_SHARED_INFO + ;; + itr.d dtr[r25]=r23 // wire in new mapping... + ;; + // Map for arch_vcpu_info_t + movl r22=SHARED_ARCHINFO_ADDR + ;; + movl r25=__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RW) + ;; + mov r21=loc7 // saved sharedinfo physical address + ;; + or r23=r25,r21 // construct PA | page properties + mov r24=PAGE_SHIFT<<2 + ;; + ptr.d r22,r24 + ;; + mov cr.itir=r24 + mov cr.ifa=r22 + ;; + mov r25=IA64_TR_ARCH_INFO + ;; + itr.d dtr[r25]=r23 // wire in new mapping... + ;; + + // done, switch back to virtual and return + mov r16=loc3 // r16= original psr + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode + mov psr.l = loc3 // restore init PSR + + mov ar.pfs = loc1 + mov rp = loc0 + ;; + mov ar.rsc=loc4 // restore RSE configuration + srlz.d // seralize restoration of psr.l + br.ret.sptk.many rp +END(ia64_new_rr7) + +#include "minstate.h" + +GLOBAL_ENTRY(ia64_prepare_handle_privop) + .prologue + /* + * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 + */ + mov r16=r0 + DO_SAVE_SWITCH_STACK + br.call.sptk.many rp=ia64_handle_privop // stack frame setup in ivt +.ret22: .body + DO_LOAD_SWITCH_STACK + br.cond.sptk.many rp // goes to ia64_leave_kernel +END(ia64_prepare_handle_privop) + +GLOBAL_ENTRY(ia64_prepare_handle_break) + .prologue + /* + * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 + */ + mov r16=r0 + DO_SAVE_SWITCH_STACK + br.call.sptk.many rp=ia64_handle_break // stack frame setup in ivt +.ret23: .body + DO_LOAD_SWITCH_STACK + br.cond.sptk.many rp // goes to ia64_leave_kernel +END(ia64_prepare_handle_break) + +GLOBAL_ENTRY(ia64_prepare_handle_reflection) + .prologue + /* + * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 + */ + mov r16=r0 + DO_SAVE_SWITCH_STACK + br.call.sptk.many rp=ia64_handle_reflection // stack frame setup in ivt +.ret24: .body + DO_LOAD_SWITCH_STACK + br.cond.sptk.many rp // goes to ia64_leave_kernel +END(ia64_prepare_handle_reflection) + +GLOBAL_ENTRY(__get_domain_bundle) + EX(.failure_in_get_bundle,ld8 r8=[r32],8) + ;; + EX(.failure_in_get_bundle,ld8 r9=[r32]) + ;; + br.ret.sptk.many rp + ;; +.failure_in_get_bundle: + mov r8=0 + ;; + mov r9=0 + ;; + br.ret.sptk.many rp + ;; +END(__get_domain_bundle) + +GLOBAL_ENTRY(dorfirfi) + movl r16 = XSI_IIP + movl r17 = XSI_IPSR + movl r18 = XSI_IFS + ;; + ld8 r16 = [r16] + ld8 r17 = [r17] + ld8 r18 = [r18] + ;; + mov cr.iip=r16 + mov cr.ipsr=r17 + mov cr.ifs=r18 + ;; + // fall through +END(dorfirfi) + +GLOBAL_ENTRY(dorfi) + rfi + ;; +END(dorfirfi) + +// +// Long's Peak UART Offsets +// +#define COM_TOP 0xff5e0000 +#define COM_BOT 0xff5e2000 + +// UART offsets +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define UART_INT_ENB 1 /* interrupt enable (DLAB=0) */ +#define UART_INT_ID 2 /* Interrupt ID register */ +#define UART_LINE_CTL 3 /* Line control register */ +#define UART_MODEM_CTL 4 /* Modem Control Register */ +#define UART_LSR 5 /* In: Line Status Register */ +#define UART_MSR 6 /* Modem status register */ +#define UART_DLATCH_LOW UART_TX +#define UART_DLATCH_HIGH UART_INT_ENB +#define COM1 0x3f8 +#define COM2 0x2F8 +#define COM3 0x3E8 + +/* interrupt enable bits (offset 1) */ +#define DATA_AVAIL_INT 1 +#define XMIT_HOLD_EMPTY_INT 2 +#define LINE_STAT_INT 4 +#define MODEM_STAT_INT 8 + +/* line status bits (offset 5) */ +#define REC_DATA_READY 1 +#define OVERRUN 2 +#define PARITY_ERROR 4 +#define FRAMING_ERROR 8 +#define BREAK_INTERRUPT 0x10 +#define XMIT_HOLD_EMPTY 0x20 +#define XMIT_SHIFT_EMPTY 0x40 + +// Write a single character +// input: r32 = character to be written +// output: none +GLOBAL_ENTRY(longs_peak_putc) + rsm psr.dt + movl r16 = 0x8000000000000000 + COM_TOP + UART_LSR + ;; + srlz.i + ;; + +.Chk_THRE_p: + ld1.acq r18=[r16] + ;; + + and r18 = XMIT_HOLD_EMPTY, r18 + ;; + cmp4.eq p6,p0=0,r18 + ;; + +(p6) br .Chk_THRE_p + ;; + movl r16 = 0x8000000000000000 + COM_TOP + UART_TX + ;; + st1.rel [r16]=r32 + ;; + ssm psr.dt + ;; + srlz.i + ;; + br.ret.sptk.many b0 +END(longs_peak_putc) + +/* derived from linux/arch/ia64/hp/sim/boot/boot_head.S */ +GLOBAL_ENTRY(pal_emulator_static) + mov r8=-1 + mov r9=256 + ;; + cmp.gtu p7,p8=r9,r32 /* r32 <= 255? */ +(p7) br.cond.sptk.few static + ;; + mov r9=512 + ;; + cmp.gtu p7,p8=r9,r32 +(p7) br.cond.sptk.few stacked + ;; +static: cmp.eq p7,p8=6,r32 /* PAL_PTCE_INFO */ +(p8) br.cond.sptk.few 1f + ;; + mov r8=0 /* status = 0 */ + movl r9=0x100000000 /* tc.base */ + movl r10=0x0000000200000003 /* count[0], count[1] */ + movl r11=0x1000000000002000 /* stride[0], stride[1] */ + br.ret.sptk.few rp +1: cmp.eq p7,p8=14,r32 /* PAL_FREQ_RATIOS */ +(p8) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + movl r9 =0x900000002 /* proc_ratio (1/100) */ + movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ + movl r11=0x900000002 /* itc_ratio<<32 (1/100) */ + ;; +1: cmp.eq p7,p8=19,r32 /* PAL_RSE_INFO */ +(p8) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + mov r9=96 /* num phys stacked */ + mov r10=0 /* hints */ + mov r11=0 + br.ret.sptk.few rp +1: cmp.eq p7,p8=1,r32 /* PAL_CACHE_FLUSH */ +(p8) br.cond.sptk.few 1f +#if 0 + mov r9=ar.lc + movl r8=524288 /* flush 512k million cache lines (16MB) */ + ;; + mov ar.lc=r8 + movl r8=0xe000000000000000 + ;; +.loop: fc r8 + add r8=32,r8 + br.cloop.sptk.few .loop + sync.i + ;; + srlz.i + ;; + mov ar.lc=r9 + mov r8=r0 + ;; +1: cmp.eq p7,p8=15,r32 /* PAL_PERF_MON_INFO */ +(p8) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + movl r9 =0x08122f04 /* generic=4 width=47 retired=8 cycles=18 */ + mov r10=0 /* reserved */ + mov r11=0 /* reserved */ + mov r16=0xffff /* implemented PMC */ + mov r17=0x3ffff /* implemented PMD */ + add r18=8,r29 /* second index */ + ;; + st8 [r29]=r16,16 /* store implemented PMC */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; + st8 [r29]=r0,16 /* clear remaining bits */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; + st8 [r29]=r17,16 /* store implemented PMD */ + st8 [r18]=r0,16 /* clear remaining bits */ + mov r16=0xf0 /* cycles count capable PMC */ + ;; + st8 [r29]=r0,16 /* clear remaining bits */ + st8 [r18]=r0,16 /* clear remaining bits */ + mov r17=0xf0 /* retired bundles capable PMC */ + ;; + st8 [r29]=r16,16 /* store cycles capable */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; + st8 [r29]=r0,16 /* clear remaining bits */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; + st8 [r29]=r17,16 /* store retired bundle capable */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; + st8 [r29]=r0,16 /* clear remaining bits */ + st8 [r18]=r0,16 /* clear remaining bits */ + ;; +1: br.cond.sptk.few rp +#else +1: +#endif +stacked: + br.ret.sptk.few rp +END(pal_emulator_static) + +GLOBAL_ENTRY(vhpt_insert) +// alloc loc0 = ar.pfs, 3, 1, 0, 0 + mov r16=r32 + mov r26=r33 + mov r27=r34 + ;; + VHPT_INSERT() +// VHPT_INSERT1() ... add collision chains later +// mov ar.pfs = loc0 + br.ret.sptk.few rp + ;; +END(vhpt_insert) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xenirq.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xenirq.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,78 @@ +/* + * Xen irq routines + * + * Copyright (C) 2005 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <asm/ptrace.h> +#include <asm/hw_irq.h> +#include <asm/delay.h> + + +void +xen_debug_irq(ia64_vector vector, struct pt_regs *regs) +{ +//FIXME: For debug only, can be removed + static char firstirq = 1; + static char firsttime[256]; + static char firstpend[256]; + if (firstirq) { + int i; + for (i=0;i<256;i++) firsttime[i] = 1; + for (i=0;i<256;i++) firstpend[i] = 1; + firstirq = 0; + } + if (firsttime[vector]) { + printf("**** (entry) First received int on vector=%d,itc=%lx\n", + (unsigned long) vector, ia64_get_itc()); + firsttime[vector] = 0; + } +} + + +int +xen_do_IRQ(ia64_vector vector) +{ + if (vector != 0xef) { + extern void vcpu_pend_interrupt(void *, int); +#if 0 + if (firsttime[vector]) { + printf("**** (iterate) First received int on vector=%d,itc=%lx\n", + (unsigned long) vector, ia64_get_itc()); + firsttime[vector] = 0; + } + if (firstpend[vector]) { + printf("**** First pended int on vector=%d,itc=%lx\n", + (unsigned long) vector,ia64_get_itc()); + firstpend[vector] = 0; + } +#endif + //FIXME: TEMPORARY HACK!!!! + vcpu_pend_interrupt(dom0->vcpu[0],vector); + vcpu_wake(dom0->vcpu[0]); + return(1); + } + return(0); +} + +/* From linux/kernel/softirq.c */ +#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED +# define invoke_softirq() __do_softirq() +#else +# define invoke_softirq() do_softirq() +#endif + +/* + * Exit an interrupt context. Process softirqs if needed and possible: + */ +void irq_exit(void) +{ + //account_system_vtime(current); + //sub_preempt_count(IRQ_EXIT_OFFSET); + if (!in_interrupt() && local_softirq_pending()) + invoke_softirq(); + //preempt_enable_no_resched(); +} +/* end from linux/kernel/softirq.c */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xenmem.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xenmem.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,86 @@ +/* + * Xen memory allocator routines + * + * Copyright (C) 2005 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + * Copyright (C) 2005 Intel Corp. + * + * Routines used by ia64 machines with contiguous (or virtually contiguous) + * memory. + */ + +#include <linux/config.h> +#include <asm/pgtable.h> +#include <xen/mm.h> + +extern struct page *zero_page_memmap_ptr; +struct pfn_info *frame_table; +unsigned long frame_table_size; +unsigned long max_page; + +struct page *mem_map; +#define MAX_DMA_ADDRESS ~0UL // FIXME??? + +#ifdef CONFIG_VIRTUAL_MEM_MAP +static unsigned long num_dma_physpages; +#endif + +/* + * Set up the page tables. + */ +#ifdef CONFIG_VTI +unsigned long *mpt_table; +unsigned long mpt_table_size; +#endif // CONFIG_VTI + +void +paging_init (void) +{ + struct pfn_info *pg; + +#ifdef CONFIG_VTI + unsigned int mpt_order; + /* Create machine to physical mapping table + * NOTE: similar to frame table, later we may need virtually + * mapped mpt table if large hole exists. Also MAX_ORDER needs + * to be changed in common code, which only support 16M by far + */ + mpt_table_size = max_page * sizeof(unsigned long); + mpt_order = get_order(mpt_table_size); + ASSERT(mpt_order <= MAX_ORDER); + if ((mpt_table = alloc_xenheap_pages(mpt_order)) == NULL) + panic("Not enough memory to bootstrap Xen.\n"); + + printk("machine to physical table: 0x%lx\n", (u64)mpt_table); + memset(mpt_table, INVALID_M2P_ENTRY, mpt_table_size); +#endif // CONFIG_VTI + + /* Other mapping setup */ + + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); +} + +/* FIXME: postpone support to machines with big holes between physical memorys. + * Current hack allows only efi memdesc upto 4G place. (See efi.c) + */ +#ifndef CONFIG_VIRTUAL_MEM_MAP +#define FT_ALIGN_SIZE (16UL << 20) +void __init init_frametable(void) +{ + unsigned long i, pfn; + frame_table_size = max_page * sizeof(struct pfn_info); + frame_table_size = (frame_table_size + PAGE_SIZE - 1) & PAGE_MASK; + + /* Request continuous trunk from boot allocator, since HV + * address is identity mapped */ + pfn = alloc_boot_pages( + frame_table_size >> PAGE_SHIFT, FT_ALIGN_SIZE >> PAGE_SHIFT); + if (pfn == 0) + panic("Not enough memory for frame table.\n"); + + frame_table = __va(pfn << PAGE_SHIFT); + memset(frame_table, 0, frame_table_size); + printk("size of frame_table: %lukB\n", + frame_table_size >> 10); +} +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xenmisc.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xenmisc.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,391 @@ +/* + * Xen misc + * + * Functions/decls that are/may be needed to link with Xen because + * of x86 dependencies + * + * Copyright (C) 2004 Hewlett-Packard Co. + * Dan Magenheimer (dan.magenheimer@xxxxxx) + * + */ + +#include <linux/config.h> +#include <xen/sched.h> +#include <linux/efi.h> +#include <asm/processor.h> +#include <xen/serial.h> +#include <asm/io.h> +#include <xen/softirq.h> + +efi_memory_desc_t ia64_efi_io_md; +EXPORT_SYMBOL(ia64_efi_io_md); +unsigned long wait_init_idle; +int phys_proc_id[NR_CPUS]; +unsigned long loops_per_jiffy = (1<<12); // from linux/init/main.c + +void unw_init(void) { printf("unw_init() skipped (NEED FOR KERNEL UNWIND)\n"); } +void ia64_mca_init(void) { printf("ia64_mca_init() skipped (Machine check abort handling)\n"); } +void ia64_mca_cpu_init(void *x) { } +void ia64_patch_mckinley_e9(unsigned long a, unsigned long b) { } +void ia64_patch_vtop(unsigned long a, unsigned long b) { } +void hpsim_setup(char **x) +{ +#ifdef CONFIG_SMP + init_smp_config(); +#endif +} + +// called from mem_init... don't think s/w I/O tlb is needed in Xen +//void swiotlb_init(void) { } ...looks like it IS needed + +long +is_platform_hp_ski(void) +{ + int i; + long cpuid[6]; + + for (i = 0; i < 5; ++i) + cpuid[i] = ia64_get_cpuid(i); + if ((cpuid[0] & 0xff) != 'H') return 0; + if ((cpuid[3] & 0xff) != 0x4) return 0; + if (((cpuid[3] >> 8) & 0xff) != 0x0) return 0; + if (((cpuid[3] >> 16) & 0xff) != 0x0) return 0; + if (((cpuid[3] >> 24) & 0x7) != 0x7) return 0; + return 1; +} + +long +platform_is_hp_ski(void) +{ + extern long running_on_sim; + return running_on_sim; +} + +/* calls in xen/common code that are unused on ia64 */ + +void sync_lazy_execstate_cpu(unsigned int cpu) {} + +#ifdef CONFIG_VTI +int grant_table_create(struct domain *d) { return 0; } +void grant_table_destroy(struct domain *d) { return; } +#endif + +struct pt_regs *guest_cpu_user_regs(void) { return ia64_task_regs(current); } + +void raise_actimer_softirq(void) +{ + raise_softirq(AC_TIMER_SOFTIRQ); +} + +#ifndef CONFIG_VTI +unsigned long +__gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) +{ + if (d == dom0) + return(gpfn); + else { + unsigned long pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT); + if (!pte) { +printk("__gpfn_to_mfn_foreign: bad gpfn. spinning...\n"); +while(1); + return 0; + } + return ((pte & _PFN_MASK) >> PAGE_SHIFT); + } +} + +u32 +__mfn_to_gpfn(struct domain *d, unsigned long frame) +{ + // FIXME: is this right? +if ((frame << PAGE_SHIFT) & _PAGE_PPN_MASK) { +printk("__mfn_to_gpfn: bad frame. spinning...\n"); +while(1); +} + return frame; +} +#endif + +#ifndef CONFIG_VTI +unsigned long __hypercall_create_continuation( + unsigned int op, unsigned int nr_args, ...) +{ + printf("__hypercall_create_continuation: not implemented!!!\n"); +} +#endif + +/////////////////////////////// + +/////////////////////////////// +// from arch/x86/apic.c +/////////////////////////////// + +extern unsigned long domain0_ready; + +int reprogram_ac_timer(s_time_t timeout) +{ + struct vcpu *v = current; + +#ifdef CONFIG_VTI +// if(VMX_DOMAIN(v)) + return 1; +#endif // CONFIG_VTI + if (!domain0_ready) return 1; + local_cpu_data->itm_next = timeout; + if (is_idle_task(v->domain)) vcpu_safe_set_itm(timeout); + else vcpu_set_next_timer(current); + return 1; +} + +/////////////////////////////// +// from arch/ia64/page_alloc.c +/////////////////////////////// +DEFINE_PER_CPU(struct page_state, page_states) = {0}; +unsigned long totalram_pages; + +void __mod_page_state(unsigned long offset, unsigned long delta) +{ + unsigned long flags; + void* ptr; + + local_irq_save(flags); + ptr = &__get_cpu_var(page_states); + *(unsigned long*)(ptr + offset) += delta; + local_irq_restore(flags); +} + +/////////////////////////////// +// from arch/x86/flushtlb.c +/////////////////////////////// + +u32 tlbflush_clock; +u32 tlbflush_time[NR_CPUS]; + +/////////////////////////////// +// from arch/x86/memory.c +/////////////////////////////// + +void init_percpu_info(void) +{ + dummy(); + //memset(percpu_info, 0, sizeof(percpu_info)); +} + +void free_page_type(struct pfn_info *page, unsigned int type) +{ + dummy(); +} + +/////////////////////////////// +//// misc memory stuff +/////////////////////////////// + +unsigned long __get_free_pages(unsigned int mask, unsigned int order) +{ + void *p = alloc_xenheap_pages(order); + + memset(p,0,PAGE_SIZE<<order); + return (unsigned long)p; +} + +void __free_pages(struct page *page, unsigned int order) +{ + if (order) BUG(); + free_xenheap_page(page); +} + +void *pgtable_quicklist_alloc(void) +{ + return alloc_xenheap_pages(0); +} + +void pgtable_quicklist_free(void *pgtable_entry) +{ + free_xenheap_page(pgtable_entry); +} + +/////////////////////////////// +// from arch/ia64/traps.c +/////////////////////////////// + +void show_registers(struct pt_regs *regs) +{ + printf("*** ADD REGISTER DUMP HERE FOR DEBUGGING\n"); +} + +int is_kernel_text(unsigned long addr) +{ + extern char _stext[], _etext[]; + if (addr >= (unsigned long) _stext && + addr <= (unsigned long) _etext) + return 1; + + return 0; +} + +unsigned long kernel_text_end(void) +{ + extern char _etext[]; + return (unsigned long) _etext; +} + +/////////////////////////////// +// from common/keyhandler.c +/////////////////////////////// +void dump_pageframe_info(struct domain *d) +{ + printk("dump_pageframe_info not implemented\n"); +} + +/////////////////////////////// +// called from arch/ia64/head.S +/////////////////////////////// + +void console_print(char *msg) +{ + printk("console_print called, how did start_kernel return???\n"); +} + +void kernel_thread_helper(void) +{ + printk("kernel_thread_helper not implemented\n"); + dummy(); +} + +void sys_exit(void) +{ + printk("sys_exit not implemented\n"); + dummy(); +} + +//////////////////////////////////// +// called from unaligned.c +//////////////////////////////////// + +void die_if_kernel(char *str, struct pt_regs *regs, long err) /* __attribute__ ((noreturn)) */ +{ + printk("die_if_kernel: called, not implemented\n"); +} + +long +ia64_peek (struct task_struct *child, struct switch_stack *child_stack, + unsigned long user_rbs_end, unsigned long addr, long *val) +{ + printk("ia64_peek: called, not implemented\n"); +} + +long +ia64_poke (struct task_struct *child, struct switch_stack *child_stack, + unsigned long user_rbs_end, unsigned long addr, long val) +{ + printk("ia64_poke: called, not implemented\n"); +} + +void +ia64_sync_fph (struct task_struct *task) +{ + printk("ia64_sync_fph: called, not implemented\n"); +} + +void +ia64_flush_fph (struct task_struct *task) +{ + printk("ia64_flush_fph: called, not implemented\n"); +} + +//////////////////////////////////// +// called from irq_ia64.c:init_IRQ() +// (because CONFIG_IA64_HP_SIM is specified) +//////////////////////////////////// +void hpsim_irq_init(void) { } + + +// accomodate linux extable.c +//const struct exception_table_entry * +void *search_module_extables(unsigned long addr) { return NULL; } +void *__module_text_address(unsigned long addr) { return NULL; } +void *module_text_address(unsigned long addr) { return NULL; } + +void cs10foo(void) {} +void cs01foo(void) {} + +unsigned long context_switch_count = 0; + +void context_switch(struct vcpu *prev, struct vcpu *next) +{ +//printk("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); +//printk("@@@@@@ context switch from domain %d (%x) to domain %d (%x)\n", +//prev->domain->domain_id,(long)prev&0xffffff,next->domain->domain_id,(long)next&0xffffff); +//if (prev->domain->domain_id == 1 && next->domain->domain_id == 0) cs10foo(); +//if (prev->domain->domain_id == 0 && next->domain->domain_id == 1) cs01foo(); +//printk("@@sw %d->%d\n",prev->domain->domain_id,next->domain->domain_id); +#ifdef CONFIG_VTI + vtm_domain_out(prev); +#endif + context_switch_count++; + switch_to(prev,next,prev); +#ifdef CONFIG_VTI + vtm_domain_in(current); +#endif + +// leave this debug for now: it acts as a heartbeat when more than +// one domain is active +{ +static long cnt[16] = { 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50}; +static int i = 100; +int id = ((struct vcpu *)current)->domain->domain_id & 0xf; +if (!cnt[id]--) { printk("%x",id); cnt[id] = 500000; } +if (!i--) { printk("+",id); i = 1000000; } +} + +#ifdef CONFIG_VTI + if (VMX_DOMAIN(current)) + vmx_load_all_rr(current); +#else + if (!is_idle_task(current->domain)) { + load_region_regs(current); + if (vcpu_timer_expired(current)) vcpu_pend_timer(current); + } + if (vcpu_timer_expired(current)) vcpu_pend_timer(current); +#endif +} + +void context_switch_finalise(struct vcpu *next) +{ + /* nothing to do */ +} + +void continue_running(struct vcpu *same) +{ + /* nothing to do */ +} + +void panic_domain(struct pt_regs *regs, const char *fmt, ...) +{ + va_list args; + char buf[128]; + struct vcpu *v = current; + static volatile int test = 1; // so can continue easily in debug + extern spinlock_t console_lock; + unsigned long flags; + +loop: + printf("$$$$$ PANIC in domain %d (k6=%p): ", + v->domain->domain_id, + __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT]); + va_start(args, fmt); + (void)vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + printf(buf); + if (regs) show_registers(regs); + domain_pause_by_systemcontroller(current->domain); + v->domain->shutdown_code = SHUTDOWN_crash; + set_bit(_DOMF_shutdown, v->domain->domain_flags); + if (v->domain->domain_id == 0) { + int i = 1000000000L; + // if domain0 crashes, just periodically print out panic + // message to make post-mortem easier + while(i--); + goto loop; + } +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xensetup.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xensetup.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,389 @@ +/****************************************************************************** + * xensetup.c + * Copyright (c) 2004-2005 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/errno.h> +//#include <xen/spinlock.h> +#include <xen/multiboot.h> +#include <xen/sched.h> +#include <xen/mm.h> +//#include <xen/delay.h> +#include <xen/compile.h> +//#include <xen/console.h> +#include <xen/serial.h> +#include <xen/trace.h> +#include <asm/meminit.h> +#include <asm/page.h> +#include <asm/setup.h> +#include <xen/string.h> + +unsigned long xenheap_phys_end; + +char saved_command_line[COMMAND_LINE_SIZE]; + +struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu }; + +cpumask_t cpu_present_map; + +#ifdef CLONE_DOMAIN0 +struct domain *clones[CLONE_DOMAIN0]; +#endif +extern unsigned long domain0_ready; + +int find_max_pfn (unsigned long, unsigned long, void *); +void start_of_day(void); + +/* opt_nosmp: If true, secondary processors are ignored. */ +static int opt_nosmp = 0; +boolean_param("nosmp", opt_nosmp); + +/* maxcpus: maximum number of CPUs to activate. */ +static unsigned int max_cpus = NR_CPUS; +integer_param("maxcpus", max_cpus); + +/* + * opt_xenheap_megabytes: Size of Xen heap in megabytes, including: + * xen image + * bootmap bits + * xen heap + * Note: To allow xenheap size configurable, the prerequisite is + * to configure elilo allowing relocation defaultly. Then since + * elilo chooses 256M as alignment when relocating, alignment issue + * on IPF can be addressed. + */ +unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB; +unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE; +extern long running_on_sim; +unsigned long xen_pstart; + +static int +xen_count_pages(u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + /* FIXME: do we need consider difference between DMA-usable memory and + * normal memory? Seems that HV has no requirement to operate DMA which + * is owned by Dom0? */ + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + +/* Find first hole after trunk for xen image */ +static int +xen_find_first_hole(u64 start, u64 end, void *arg) +{ + unsigned long *first_hole = arg; + + if ((*first_hole) == 0) { + if ((start <= KERNEL_START) && (KERNEL_START < end)) + *first_hole = __pa(end); + } + + return 0; +} + +static void __init do_initcalls(void) +{ + initcall_t *call; + for ( call = &__initcall_start; call < &__initcall_end; call++ ) + (*call)(); +} + +/* + * IPF loader only supports one commaind line currently, for + * both xen and guest kernel. This function provides pre-parse + * to mixed command line, to split it into two parts. + * + * User should split the parameters by "--", with strings after + * spliter for guest kernel. Missing "--" means whole line belongs + * to guest. Example: + * "com2=57600,8n1 console=com2 -- console=ttyS1 console=tty + * root=/dev/sda3 ro" + */ +static char null[4] = { 0 }; + +void early_cmdline_parse(char **cmdline_p) +{ + char *guest_cmd; + char *split = "--"; + + if (*cmdline_p == NULL) { + *cmdline_p = &null[0]; + saved_command_line[0] = '\0'; + return; + } + + guest_cmd = strstr(*cmdline_p, split); + /* If no spliter, whole line is for guest */ + if (guest_cmd == NULL) { + guest_cmd = *cmdline_p; + *cmdline_p = &null[0]; + } else { + *guest_cmd = '\0'; /* Split boot parameters for xen and guest */ + guest_cmd += strlen(split); + while (*guest_cmd == ' ') guest_cmd++; + } + + strlcpy(saved_command_line, guest_cmd, COMMAND_LINE_SIZE); + return; +} + +struct ns16550_defaults ns16550_com1 = { + .baud = BAUD_AUTO, + .data_bits = 8, + .parity = 'n', + .stop_bits = 1 +}; + +struct ns16550_defaults ns16550_com2 = { + .baud = BAUD_AUTO, + .data_bits = 8, + .parity = 'n', + .stop_bits = 1 +}; + +void start_kernel(void) +{ + unsigned char *cmdline; + void *heap_start; + int i; + unsigned long max_mem, nr_pages, firsthole_start; + unsigned long dom0_memory_start, dom0_memory_end; + unsigned long initial_images_start, initial_images_end; + + running_on_sim = is_platform_hp_ski(); + /* Kernel may be relocated by EFI loader */ + xen_pstart = ia64_tpa(KERNEL_START); + + /* Must do this early -- e.g., spinlocks rely on get_current(). */ + //set_current(&idle0_vcpu); + ia64_r13 = (void *)&idle0_vcpu; + idle0_vcpu.domain = &idle0_domain; + + early_setup_arch(&cmdline); + + /* We initialise the serial devices very early so we can get debugging. */ + if (running_on_sim) hpsim_serial_init(); + else { + ns16550_init(0, &ns16550_com1); + /* Also init com2 for Tiger4. */ + ns16550_com2.io_base = 0x2f8; + ns16550_com2.irq = 3; + ns16550_init(1, &ns16550_com2); + } + serial_init_preirq(); + + init_console(); + set_printk_prefix("(XEN) "); + + /* xenheap should be in same TR-covered range with xen image */ + xenheap_phys_end = xen_pstart + xenheap_size; + printk("xen image pstart: 0x%lx, xenheap pend: 0x%lx\n", + xen_pstart, xenheap_phys_end); + + /* Find next hole */ + firsthole_start = 0; + efi_memmap_walk(xen_find_first_hole, &firsthole_start); + + initial_images_start = xenheap_phys_end; + initial_images_end = initial_images_start + ia64_boot_param->initrd_size; + + /* Later may find another memory trunk, even away from xen image... */ + if (initial_images_end > firsthole_start) { + printk("Not enough memory to stash the DOM0 kernel image.\n"); + printk("First hole:0x%lx, relocation end: 0x%lx\n", + firsthole_start, initial_images_end); + for ( ; ; ); + } + + /* This copy is time consuming, but elilo may load Dom0 image + * within xenheap range */ + printk("ready to move Dom0 to 0x%lx...", initial_images_start); + memmove(__va(initial_images_start), + __va(ia64_boot_param->initrd_start), + ia64_boot_param->initrd_size); + ia64_boot_param->initrd_start = initial_images_start; + printk("Done\n"); + + /* first find highest page frame number */ + max_page = 0; + efi_memmap_walk(find_max_pfn, &max_page); + printf("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page); + + heap_start = memguard_init(ia64_imva(&_end)); + printf("Before heap_start: 0x%lx\n", heap_start); + heap_start = __va(init_boot_allocator(__pa(heap_start))); + printf("After heap_start: 0x%lx\n", heap_start); + + reserve_memory(); + + efi_memmap_walk(filter_rsvd_memory, init_boot_pages); + efi_memmap_walk(xen_count_pages, &nr_pages); + + printk("System RAM: %luMB (%lukB)\n", + nr_pages >> (20 - PAGE_SHIFT), + nr_pages << (PAGE_SHIFT - 10)); + + init_frametable(); + + ia64_fph_enable(); + __ia64_init_fpu(); + + alloc_dom0(); +#ifdef DOMU_BUILD_STAGING + alloc_domU_staging(); +#endif + + end_boot_allocator(); + + init_xenheap_pages(__pa(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); + + late_setup_arch(&cmdline); + setup_per_cpu_areas(); + mem_init(); + +printk("About to call scheduler_init()\n"); + scheduler_init(); + local_irq_disable(); +printk("About to call xen_time_init()\n"); + xen_time_init(); +#ifdef CONFIG_VTI + init_xen_time(); /* initialise the time */ +#endif // CONFIG_VTI +printk("About to call ac_timer_init()\n"); + ac_timer_init(); +// init_xen_time(); ??? + +#ifdef CONFIG_SMP + if ( opt_nosmp ) + { + max_cpus = 0; + smp_num_siblings = 1; + //boot_cpu_data.x86_num_cores = 1; + } + + smp_prepare_cpus(max_cpus); + + /* We aren't hotplug-capable yet. */ + //BUG_ON(!cpus_empty(cpu_present_map)); + for_each_cpu ( i ) + cpu_set(i, cpu_present_map); + + //BUG_ON(!local_irq_is_enabled()); + +printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); + for_each_present_cpu ( i ) + { + if ( num_online_cpus() >= max_cpus ) + break; + if ( !cpu_online(i) ) { +printk("About to call __cpu_up(%d)\n",i); + __cpu_up(i); + } + } + + printk("Brought up %ld CPUs\n", (long)num_online_cpus()); + smp_cpus_done(max_cpus); +#endif + + + // FIXME: Should the following be swapped and moved later? + schedulers_start(); + do_initcalls(); +printk("About to call sort_main_extable()\n"); + sort_main_extable(); + + /* surrender usage of kernel registers to domain, use percpu area instead */ + __get_cpu_var(cpu_kr)._kr[IA64_KR_IO_BASE] = ia64_get_kr(IA64_KR_IO_BASE); + __get_cpu_var(cpu_kr)._kr[IA64_KR_PER_CPU_DATA] = ia64_get_kr(IA64_KR_PER_CPU_DATA); + __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT_STACK] = ia64_get_kr(IA64_KR_CURRENT_STACK); + __get_cpu_var(cpu_kr)._kr[IA64_KR_FPU_OWNER] = ia64_get_kr(IA64_KR_FPU_OWNER); + __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT] = ia64_get_kr(IA64_KR_CURRENT); + __get_cpu_var(cpu_kr)._kr[IA64_KR_PT_BASE] = ia64_get_kr(IA64_KR_PT_BASE); + + /* Create initial domain 0. */ +printk("About to call do_createdomain()\n"); + dom0 = do_createdomain(0, 0); + init_task.domain = &idle0_domain; + init_task.processor = 0; +// init_task.mm = &init_mm; + init_task.domain->arch.mm = &init_mm; +// init_task.thread = INIT_THREAD; + //arch_do_createdomain(current); +#ifdef CLONE_DOMAIN0 + { + int i; + for (i = 0; i < CLONE_DOMAIN0; i++) { + clones[i] = do_createdomain(i+1, 0); + if ( clones[i] == NULL ) + panic("Error creating domain0 clone %d\n",i); + } + } +#endif + if ( dom0 == NULL ) + panic("Error creating domain 0\n"); + + set_bit(_DOMF_privileged, &dom0->domain_flags); + + /* + * We're going to setup domain0 using the module(s) that we stashed safely + * above our heap. The second module, if present, is an initrd ramdisk. + */ +printk("About to call construct_dom0()\n"); + dom0_memory_start = __va(ia64_boot_param->initrd_start); + dom0_memory_end = ia64_boot_param->initrd_size; + if ( construct_dom0(dom0, dom0_memory_start, dom0_memory_end, + 0, + 0, + 0) != 0) + panic("Could not set up DOM0 guest OS\n"); +#ifdef CLONE_DOMAIN0 + { + int i; + dom0_memory_start = __va(ia64_boot_param->initrd_start); + dom0_memory_end = ia64_boot_param->initrd_size; + for (i = 0; i < CLONE_DOMAIN0; i++) { +printk("CONSTRUCTING DOMAIN0 CLONE #%d\n",i+1); + if ( construct_domU(clones[i], dom0_memory_start, dom0_memory_end, + 0, + 0, + 0) != 0) + panic("Could not set up DOM0 clone %d\n",i); + } + } +#endif + + /* The stash space for the initial kernel image can now be freed up. */ + init_domheap_pages(ia64_boot_param->initrd_start, + ia64_boot_param->initrd_start + ia64_boot_param->initrd_size); + if (!running_on_sim) // slow on ski and pages are pre-initialized to zero + scrub_heap_pages(); + +printk("About to call init_trace_bufs()\n"); + init_trace_bufs(); + + /* Give up the VGA console if DOM0 is configured to grab it. */ +#ifndef IA64 + console_endboot(cmdline && strstr(cmdline, "tty0")); +#endif + +#ifdef CLONE_DOMAIN0 + { + int i; + for (i = 0; i < CLONE_DOMAIN0; i++) + domain_unpause_by_systemcontroller(clones[i]); + } +#endif + domain_unpause_by_systemcontroller(dom0); + domain0_ready = 1; + local_irq_enable(); +printk("About to call startup_cpu_idle_loop()\n"); + startup_cpu_idle_loop(); +} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen/xentime.c --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/arch/ia64/xen/xentime.c Thu Sep 1 18:46:28 2005 @@ -0,0 +1,382 @@ +/* + * xen/arch/ia64/time.c + * + * Copyright (C) 2005 Hewlett-Packard Co + * Dan Magenheimer <dan.magenheimer@xxxxxx> + */ + +#include <linux/config.h> + +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/profile.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/interrupt.h> +#include <linux/efi.h> +#include <linux/profile.h> +#include <linux/timex.h> + +#include <asm/machvec.h> +#include <asm/delay.h> +#include <asm/hw_irq.h> +#include <asm/ptrace.h> +#include <asm/sal.h> +#include <asm/sections.h> +#include <asm/system.h> +#ifdef XEN +#include <asm/vcpu.h> +#include <linux/jiffies.h> // not included by xen/sched.h +#endif +#include <xen/softirq.h> + +#ifdef XEN +seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; +#endif + +#define TIME_KEEPER_ID 0 +extern unsigned long wall_jiffies; + +static s_time_t stime_irq; /* System time at last 'time update' */ + +unsigned long domain0_ready = 0; + +#ifndef CONFIG_VTI +static inline u64 get_time_delta(void) +{ + return ia64_get_itc(); +} +#else // CONFIG_VTI +static s_time_t stime_irq = 0x0; /* System time at last 'time update' */ +unsigned long itc_scale; +unsigned long itc_at_irq; +static unsigned long wc_sec, wc_nsec; /* UTC time at last 'time update'. */ +//static rwlock_t time_lock = RW_LOCK_UNLOCKED; +static irqreturn_t vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs); + +static inline u64 get_time_delta(void) +{ + s64 delta_itc; + u64 delta, cur_itc; + + cur_itc = ia64_get_itc(); + + delta_itc = (s64)(cur_itc - itc_at_irq); + if ( unlikely(delta_itc < 0) ) delta_itc = 0; + delta = ((u64)delta_itc) * itc_scale; + delta = delta >> 32; + + return delta; +} + +u64 tick_to_ns(u64 tick) +{ + return (tick * itc_scale) >> 32; +} +#endif // CONFIG_VTI + +s_time_t get_s_time(void) +{ + s_time_t now; + unsigned long flags; + + read_lock_irqsave(&xtime_lock, flags); + + now = stime_irq + get_time_delta(); + + /* Ensure that the returned system time is monotonically increasing. */ + { + static s_time_t prev_now = 0; + if ( unlikely(now < prev_now) ) + now = prev_now; + prev_now = now; + } + + read_unlock_irqrestore(&xtime_lock, flags); + + return now; +} + +void update_dom_time(struct vcpu *v) +{ +// FIXME: implement this? +// printf("update_dom_time: called, not implemented, skipping\n"); + return; +} + +/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */ +void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) +{ +#ifdef CONFIG_VTI + u64 _nsecs; + + write_lock_irq(&xtime_lock); + + _nsecs = (u64)nsecs + (s64)(stime_irq - system_time_base); + while ( _nsecs >= 1000000000 ) + { + _nsecs -= 1000000000; + secs++; + } + + wc_sec = secs; + wc_nsec = (unsigned long)_nsecs; + + write_unlock_irq(&xtime_lock); + + update_dom_time(current->domain); +#else +// FIXME: Should this be do_settimeofday (from linux)??? + printf("do_settime: called, not implemented, stopping\n"); + dummy(); +#endif +} + +irqreturn_t +xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long new_itm; + +#define HEARTBEAT_FREQ 16 // period in seconds +#ifdef HEARTBEAT_FREQ + static long count = 0; + if (!(++count & ((HEARTBEAT_FREQ*1024)-1))) { + printf("Heartbeat... iip=%p,psr.i=%d,pend=%d\n", + regs->cr_iip, + VCPU(current,interrupt_delivery_enabled), + VCPU(current,pending_interruption)); + count = 0; + } +#endif +#ifndef XEN + if (unlikely(cpu_is_offline(smp_processor_id()))) { + return IRQ_HANDLED; + } +#endif +#ifdef XEN + if (current->domain == dom0) { + // FIXME: there's gotta be a better way of doing this... + // We have to ensure that domain0 is launched before we + // call vcpu_timer_expired on it + //domain0_ready = 1; // moved to xensetup.c + VCPU(current,pending_interruption) = 1; + } + if (domain0_ready && vcpu_timer_expired(dom0->vcpu[0])) { + vcpu_pend_timer(dom0->vcpu[0]); + //vcpu_set_next_timer(dom0->vcpu[0]); + vcpu_wake(dom0->vcpu[0]); + } + if (!is_idle_task(current->domain) && current->domain != dom0) { + if (vcpu_timer_expired(current)) { + vcpu_pend_timer(current); + // ensure another timer interrupt happens even if domain doesn't + vcpu_set_next_timer(current); + vcpu_wake(current); + } + } + raise_actimer_softirq(); +#endif + +#ifndef XEN + platform_timer_interrupt(irq, dev_id, regs); +#endif + + new_itm = local_cpu_data->itm_next; + + if (!time_after(ia64_get_itc(), new_itm)) +#ifdef XEN + return; +#else + printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", + ia64_get_itc(), new_itm); +#endif + +#ifdef XEN +// printf("GOT TO HERE!!!!!!!!!!!\n"); + //while(1); +#else + profile_tick(CPU_PROFILING, regs); +#endif + + while (1) { +#ifndef XEN + update_process_times(user_mode(regs)); +#endif + + new_itm += local_cpu_data->itm_delta; + + if (smp_processor_id() == TIME_KEEPER_ID) { + /* + * Here we are in the timer irq handler. We have irqs locally + * disabled, but we don't know if the timer_bh is running on + * 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; +#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; + } + + do { + /* + * If we're too close to the next clock tick for + * comfort, we increase the safety margin by + * intentionally dropping the next tick(s). We do NOT + * update itm.next because that would force us to call + * do_timer() which in turn would let our clock run + * too fast (with the potentially devastating effect + * of losing monotony of time). + */ + while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) + new_itm += local_cpu_data->itm_delta; +//#ifdef XEN +// vcpu_set_next_timer(current); +//#else +//printf("***** timer_interrupt: Setting itm to %lx\n",new_itm); + ia64_set_itm(new_itm); +//#endif + /* double check, in case we got hit by a (slow) PMI: */ + } while (time_after_eq(ia64_get_itc(), new_itm)); + return IRQ_HANDLED; +} + +static struct irqaction xen_timer_irqaction = { +#ifdef CONFIG_VTI + .handler = vmx_timer_interrupt, +#else // CONFIG_VTI + .handler = xen_timer_interrupt, +#endif // CONFIG_VTI +#ifndef XEN + .flags = SA_INTERRUPT, +#endif + .name = "timer" +}; + +void __init +xen_time_init (void) +{ + register_percpu_irq(IA64_TIMER_VECTOR, &xen_timer_irqaction); + ia64_init_itm(); +} + + +#ifdef CONFIG_VTI + +/* Late init function (after all CPUs are booted). */ +int __init init_xen_time() +{ + struct timespec tm; + + itc_scale = 1000000000UL << 32 ; + itc_scale /= local_cpu_data->itc_freq; + + /* System time ticks from zero. */ + stime_irq = (s_time_t)0; + itc_at_irq = ia64_get_itc(); + + /* Wallclock time starts as the initial RTC time. */ + efi_gettimeofday(&tm); + wc_sec = tm.tv_sec; + wc_nsec = tm.tv_nsec; + + + printk("Time init:\n"); + printk(".... System Time: %ldns\n", NOW()); + printk(".... scale: %16lX\n", itc_scale); + printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_nsec/1000); + + return 0; +} + +static irqreturn_t +vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long new_itm; + struct vcpu *v = current; + + + new_itm = local_cpu_data->itm_next; + + if (!time_after(ia64_get_itc(), new_itm)) + return; + + while (1) { +#ifdef CONFIG_SMP + /* + * For UP, this is done in do_timer(). Weird, but + * fixing that would require updates to all + * platforms. + */ + update_process_times(user_mode(v, regs)); +#endif + new_itm += local_cpu_data->itm_delta; + + if (smp_processor_id() == TIME_KEEPER_ID) { + /* + * Here we are in the timer irq handler. We have irqs locally + * disabled, but we don't know if the timer_bh is running on + * another CPU. We need to avoid to SMP race by acquiring the + * xtime_lock. + */ + local_cpu_data->itm_next = new_itm; + + write_lock_irq(&xtime_lock); + /* Update jiffies counter. */ + (*(unsigned long *)&jiffies_64)++; + + /* Update wall time. */ + wc_nsec += 1000000000/HZ; + if ( wc_nsec >= 1000000000 ) + { + wc_nsec -= 1000000000; + wc_sec++; + } + + /* Updates system time (nanoseconds since boot). */ + stime_irq += MILLISECS(1000/HZ); + itc_at_irq = ia64_get_itc(); + + write_unlock_irq(&xtime_lock); + + } else + local_cpu_data->itm_next = new_itm; + + if (time_after(new_itm, ia64_get_itc())) + break; + } + + do { + /* + * If we're too close to the next clock tick for + * comfort, we increase the safety margin by + * intentionally dropping the next tick(s). We do NOT + * update itm.next because that would force us to call + * do_timer() which in turn would let our clock run + * too fast (with the potentially devastating effect + * of losing monotony of time). + */ + while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) + new_itm += local_cpu_data->itm_delta; + ia64_set_itm(new_itm); + /* double check, in case we got hit by a (slow) PMI: */ + } while (time_after_eq(ia64_get_itc(), new_itm)); + raise_softirq(AC_TIMER_SOFTIRQ); + + return IRQ_HANDLED; +} +#endif // CONFIG_VTI + diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux-xen/asm/pgtable.h --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux-xen/asm/pgtable.h Thu Sep 1 18:46:28 2005 @@ -0,0 +1,577 @@ +#ifndef _ASM_IA64_PGTABLE_H +#define _ASM_IA64_PGTABLE_H + +/* + * This file contains the functions and defines necessary to modify and use + * the IA-64 page table tree. + * + * This hopefully works with any (fixed) IA-64 page-size, as defined + * in <asm/page.h>. + * + * Copyright (C) 1998-2005 Hewlett-Packard Co + * David Mosberger-Tang <davidm@xxxxxxxxxx> + */ + +#include <linux/config.h> + +#include <asm/mman.h> +#include <asm/page.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/types.h> +#ifdef XEN +#ifndef __ASSEMBLY__ +#include <xen/sched.h> /* needed for mm_struct (via asm/domain.h) */ +#endif +#endif + +#define IA64_MAX_PHYS_BITS 50 /* max. number of physical address bits (architected) */ + +/* + * First, define the various bits in a PTE. Note that the PTE format + * matches the VHPT short format, the firt doubleword of the VHPD long + * format, and the first doubleword of the TLB insertion format. + */ +#define _PAGE_P_BIT 0 +#define _PAGE_A_BIT 5 +#define _PAGE_D_BIT 6 + +#define _PAGE_P (1 << _PAGE_P_BIT) /* page present bit */ +#define _PAGE_MA_WB (0x0 << 2) /* write back memory attribute */ +#define _PAGE_MA_UC (0x4 << 2) /* uncacheable memory attribute */ +#define _PAGE_MA_UCE (0x5 << 2) /* UC exported attribute */ +#define _PAGE_MA_WC (0x6 << 2) /* write coalescing memory attribute */ +#define _PAGE_MA_NAT (0x7 << 2) /* not-a-thing attribute */ +#define _PAGE_MA_MASK (0x7 << 2) +#define _PAGE_PL_0 (0 << 7) /* privilege level 0 (kernel) */ +#define _PAGE_PL_1 (1 << 7) /* privilege level 1 (unused) */ +#define _PAGE_PL_2 (2 << 7) /* privilege level 2 (unused) */ +#define _PAGE_PL_3 (3 << 7) /* privilege level 3 (user) */ +#define _PAGE_PL_MASK (3 << 7) +#define _PAGE_AR_R (0 << 9) /* read only */ +#define _PAGE_AR_RX (1 << 9) /* read & execute */ +#define _PAGE_AR_RW (2 << 9) /* read & write */ +#define _PAGE_AR_RWX (3 << 9) /* read, write & execute */ +#define _PAGE_AR_R_RW (4 << 9) /* read / read & write */ +#define _PAGE_AR_RX_RWX (5 << 9) /* read & exec / read, write & exec */ +#define _PAGE_AR_RWX_RW (6 << 9) /* read, write & exec / read & write */ +#define _PAGE_AR_X_RX (7 << 9) /* exec & promote / read & exec */ +#define _PAGE_AR_MASK (7 << 9) +#define _PAGE_AR_SHIFT 9 +#define _PAGE_A (1 << _PAGE_A_BIT) /* page accessed bit */ +#define _PAGE_D (1 << _PAGE_D_BIT) /* page dirty bit */ +#define _PAGE_PPN_MASK (((__IA64_UL(1) << IA64_MAX_PHYS_BITS) - 1) & ~0xfffUL) +#define _PAGE_ED (__IA64_UL(1) << 52) /* exception deferral */ +#define _PAGE_PROTNONE (__IA64_UL(1) << 63) + +/* Valid only for a PTE with the present bit cleared: */ +#define _PAGE_FILE (1 << 1) /* see swap & file pte remarks below */ + +#define _PFN_MASK _PAGE_PPN_MASK +/* Mask of bits which may be changed by pte_modify(); the odd bits are there for _PAGE_PROTNONE */ +#define _PAGE_CHG_MASK (_PAGE_P | _PAGE_PROTNONE | _PAGE_PL_MASK | _PAGE_AR_MASK | _PAGE_ED) + +#define _PAGE_SIZE_4K 12 +#define _PAGE_SIZE_8K 13 +#define _PAGE_SIZE_16K 14 +#define _PAGE_SIZE_64K 16 +#define _PAGE_SIZE_256K 18 +#define _PAGE_SIZE_1M 20 +#define _PAGE_SIZE_4M 22 +#define _PAGE_SIZE_16M 24 +#define _PAGE_SIZE_64M 26 +#define _PAGE_SIZE_256M 28 +#define _PAGE_SIZE_1G 30 +#define _PAGE_SIZE_4G 32 + +#define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB +#define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB +#define __DIRTY_BITS _PAGE_ED | __DIRTY_BITS_NO_ED + +/* + * Definitions for first level: + * + * PGDIR_SHIFT determines what a first-level page table entry can map. + */ +#define PGDIR_SHIFT (PAGE_SHIFT + 2*(PAGE_SHIFT-3)) +#define PGDIR_SIZE (__IA64_UL(1) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PTRS_PER_PGD (1UL << (PAGE_SHIFT-3)) +#define USER_PTRS_PER_PGD (5*PTRS_PER_PGD/8) /* regions 0-4 are user regions */ +#define FIRST_USER_ADDRESS 0 + +/* + * Definitions for second level: + * + * PMD_SHIFT determines the size of the area a second-level page table + * can map. + */ +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PTRS_PER_PMD (1UL << (PAGE_SHIFT-3)) + +/* + * Definitions for third level: + */ +#define PTRS_PER_PTE (__IA64_UL(1) << (PAGE_SHIFT-3)) + +/* + * All the normal masks have the "page accessed" bits on, as any time + * they are used, the page is accessed. They are cleared only by the + * page-out routines. + */ +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_A) +#define PAGE_SHARED __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RW) +#define PAGE_READONLY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +#define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +#define PAGE_COPY_EXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) +#define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) +#define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) +#define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX) + +# ifndef __ASSEMBLY__ + +#include <asm/bitops.h> +#include <asm/cacheflush.h> +#include <asm/mmu_context.h> +#include <asm/processor.h> + +/* + * Next come the mappings that determine how mmap() protection bits + * (PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE) get implemented. The + * _P version gets used for a private shared memory segment, the _S + * version gets used for a shared memory segment with MAP_SHARED on. + * In a private shared memory segment, we do a copy-on-write if a task + * attempts to write to the page. + */ + /* xwr */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_READONLY /* write to priv pg -> copy & make writable */ +#define __P011 PAGE_READONLY /* ditto */ +#define __P100 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_X_RX) +#define __P101 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) +#define __P110 PAGE_COPY_EXEC +#define __P111 PAGE_COPY_EXEC + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED /* we don't have (and don't need) write-only */ +#define __S011 PAGE_SHARED +#define __S100 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_X_RX) +#define __S101 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) +#define __S110 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RWX) +#define __S111 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RWX) + +#define pgd_ERROR(e) printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) +#define pmd_ERROR(e) printk("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) +#define pte_ERROR(e) printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) + + +/* + * Some definitions to translate between mem_map, PTEs, and page addresses: + */ + + +/* Quick test to see if ADDR is a (potentially) valid physical address. */ +static inline long +ia64_phys_addr_valid (unsigned long addr) +{ + return (addr & (local_cpu_data->unimpl_pa_mask)) == 0; +} + +/* + * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel + * memory. For the return value to be meaningful, ADDR must be >= + * PAGE_OFFSET. This operation can be relatively expensive (e.g., + * require a hash-, or multi-level tree-lookup or something of that + * sort) but it guarantees to return TRUE only if accessing the page + * at that address does not cause an error. Note that there may be + * addresses for which kern_addr_valid() returns FALSE even though an + * access would not cause an error (e.g., this is typically true for + * memory mapped I/O regions. + * + * XXX Need to implement this for IA-64. + */ +#define kern_addr_valid(addr) (1) + + +/* + * Now come the defines and routines to manage and access the three-level + * page table. + */ + +/* + * On some architectures, special things need to be done when setting + * the PTE in a page table. Nothing special needs to be on IA-64. + */ +#define set_pte(ptep, pteval) (*(ptep) = (pteval)) +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +#define RGN_SIZE (1UL << 61) +#define RGN_KERNEL 7 + +#define VMALLOC_START 0xa000000200000000UL +#ifdef CONFIG_VIRTUAL_MEM_MAP +# define VMALLOC_END_INIT (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9))) +# define VMALLOC_END vmalloc_end + extern unsigned long vmalloc_end; +#else +# define VMALLOC_END (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9))) +#endif + +/* fs/proc/kcore.c */ +#define kc_vaddr_to_offset(v) ((v) - 0xa000000000000000UL) +#define kc_offset_to_vaddr(o) ((o) + 0xa000000000000000UL) + +/* + * Conversion functions: convert page frame number (pfn) and a protection value to a page + * table entry (pte). + */ +#define pfn_pte(pfn, pgprot) \ +({ pte_t __pte; pte_val(__pte) = ((pfn) << PAGE_SHIFT) | pgprot_val(pgprot); __pte; }) + +/* Extract pfn from pte. */ +#define pte_pfn(_pte) ((pte_val(_pte) & _PFN_MASK) >> PAGE_SHIFT) + +#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + +/* This takes a physical page address that is used by the remapping functions */ +#define mk_pte_phys(physpage, pgprot) \ +({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; }) + +#define pte_modify(_pte, newprot) \ + (__pte((pte_val(_pte) & ~_PAGE_CHG_MASK) | (pgprot_val(newprot) & _PAGE_CHG_MASK))) + +#define page_pte_prot(page,prot) mk_pte(page, prot) +#define page_pte(page) page_pte_prot(page, __pgprot(0)) + +#define pte_none(pte) (!pte_val(pte)) +#define pte_present(pte) (pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE)) +#define pte_clear(mm,addr,pte) (pte_val(*(pte)) = 0UL) +/* pte_page() returns the "struct page *" corresponding to the PTE: */ +#define pte_page(pte) virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET)) + +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd))) +#define pmd_present(pmd) (pmd_val(pmd) != 0UL) +#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) +#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK)) +#define pmd_page(pmd) virt_to_page((pmd_val(pmd) + PAGE_OFFSET)) + +#define pud_none(pud) (!pud_val(pud)) +#define pud_bad(pud) (!ia64_phys_addr_valid(pud_val(pud))) +#define pud_present(pud) (pud_val(pud) != 0UL) +#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) + +#define pud_page(pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK)) + +/* + * The following have defined behavior only work if pte_present() is true. + */ +#define pte_user(pte) ((pte_val(pte) & _PAGE_PL_MASK) == _PAGE_PL_3) +#define pte_read(pte) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) < 6) +#define pte_write(pte) ((unsigned) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) - 2) <= 4) +#define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0) +#define pte_dirty(pte) ((pte_val(pte) & _PAGE_D) != 0) +#define pte_young(pte) ((pte_val(pte) & _PAGE_A) != 0) +#define pte_file(pte) ((pte_val(pte) & _PAGE_FILE) != 0) +/* + * Note: we convert AR_RWX to AR_RX and AR_RW to AR_R by clearing the 2nd bit in the + * access rights: + */ +#define pte_wrprotect(pte) (__pte(pte_val(pte) & ~_PAGE_AR_RW)) +#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_AR_RW)) +#define pte_mkexec(pte) (__pte(pte_val(pte) | _PAGE_AR_RX)) +#define pte_mkold(pte) (__pte(pte_val(pte) & ~_PAGE_A)) +#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_A)) +#define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D)) +#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D)) +#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_P)) + +/* + * Macro to a page protection value as "uncacheable". Note that "protection" is really a + * misnomer here as the protection value contains the memory attribute bits, dirty bits, + * and various other bits as well. + */ +#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) + +/* + * Macro to make mark a page protection value as "write-combining". + * Note that "protection" is really a misnomer here as the protection + * value contains the memory attribute bits, dirty bits, and various + * other bits as well. Accesses through a write-combining translation + * works bypasses the caches, but does allow for consecutive writes to + * be combined into single (but larger) write transactions. + */ +#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) + +static inline unsigned long +pgd_index (unsigned long address) +{ + unsigned long region = address >> 61; + unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1); + + return (region << (PAGE_SHIFT - 6)) | l1index; +} + +/* The offset in the 1-level directory is given by the 3 region bits + (61..63) and the level-1 bits. */ +static inline pgd_t* +pgd_offset (struct mm_struct *mm, unsigned long address) +{ + return mm->pgd + pgd_index(address); +} + +/* In the kernel's mapped region we completely ignore the region number + (since we know it's in region number 5). */ +#define pgd_offset_k(addr) \ + (init_mm.pgd + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))) + +/* Look up a pgd entry in the gate area. On IA-64, the gate-area + resides in the kernel-mapped segment, hence we use pgd_offset_k() + here. */ +#define pgd_offset_gate(mm, addr) pgd_offset_k(addr) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(dir,addr) \ + ((pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) + +/* + * Find an entry in the third-level page table. This looks more complicated than it + * should be because some platforms place page tables in high memory. + */ +#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr)) +#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr) +#define pte_offset_map_nested(dir,addr) pte_offset_map(dir, addr) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + +/* atomic versions of the some PTE manipulations: */ + +static inline int +ptep_test_and_clear_young (struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) +{ +#ifdef CONFIG_SMP + if (!pte_young(*ptep)) + return 0; + return test_and_clear_bit(_PAGE_A_BIT, ptep); +#else + pte_t pte = *ptep; + if (!pte_young(pte)) + return 0; + set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte)); + return 1; +#endif +} + +static inline int +ptep_test_and_clear_dirty (struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) +{ +#ifdef CONFIG_SMP + if (!pte_dirty(*ptep)) + return 0; + return test_and_clear_bit(_PAGE_D_BIT, ptep); +#else + pte_t pte = *ptep; + if (!pte_dirty(pte)) + return 0; + set_pte_at(vma->vm_mm, addr, ptep, pte_mkclean(pte)); + return 1; +#endif +} + +static inline pte_t +ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ +#ifdef CONFIG_SMP + return __pte(xchg((long *) ptep, 0)); +#else + pte_t pte = *ptep; + pte_clear(mm, addr, ptep); + return pte; +#endif +} + +static inline void +ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ +#ifdef CONFIG_SMP + unsigned long new, old; + + do { + old = pte_val(*ptep); + new = pte_val(pte_wrprotect(__pte (old))); + } while (cmpxchg((unsigned long *) ptep, old, new) != old); +#else + pte_t old_pte = *ptep; + set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); +#endif +} + +static inline int +pte_same (pte_t a, pte_t b) +{ + return pte_val(a) == pte_val(b); +} + +#define update_mmu_cache(vma, address, pte) do { } while (0) + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern void paging_init (void); + +/* + * Note: The macros below rely on the fact that MAX_SWAPFILES_SHIFT <= number of + * bits in the swap-type field of the swap pte. It would be nice to + * enforce that, but we can't easily include <linux/swap.h> here. + * (Of course, better still would be to define MAX_SWAPFILES_SHIFT here...). + * + * Format of swap pte: + * bit 0 : present bit (must be zero) + * bit 1 : _PAGE_FILE (must be zero) + * bits 2- 8: swap-type + * bits 9-62: swap offset + * bit 63 : _PAGE_PROTNONE bit + * + * Format of file pte: + * bit 0 : present bit (must be zero) + * bit 1 : _PAGE_FILE (must be one) + * bits 2-62: file_offset/PAGE_SIZE + * bit 63 : _PAGE_PROTNONE bit + */ +#define __swp_type(entry) (((entry).val >> 2) & 0x7f) +#define __swp_offset(entry) (((entry).val << 1) >> 10) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((long) (offset) << 9) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define PTE_FILE_MAX_BITS 61 +#define pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3) +#define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE }) + +/* XXX is this right? */ +#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ + remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) + +#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + remap_pfn_range(vma, vaddr, pfn, size, prot) + +#define MK_IOSPACE_PFN(space, pfn) (pfn) +#define GET_IOSPACE(pfn) 0 +#define GET_PFN(pfn) (pfn) + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; +extern struct page *zero_page_memmap_ptr; +#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr) + +/* We provide our own get_unmapped_area to cope with VA holes for userland */ +#define HAVE_ARCH_UNMAPPED_AREA + +#ifdef CONFIG_HUGETLB_PAGE +#define HUGETLB_PGDIR_SHIFT (HPAGE_SHIFT + 2*(PAGE_SHIFT-3)) +#define HUGETLB_PGDIR_SIZE (__IA64_UL(1) << HUGETLB_PGDIR_SHIFT) +#define HUGETLB_PGDIR_MASK (~(HUGETLB_PGDIR_SIZE-1)) +struct mmu_gather; +void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr, + unsigned long end, unsigned long floor, unsigned long ceiling); +#endif + +/* + * IA-64 doesn't have any external MMU info: the page tables contain all the necessary + * information. However, we use this routine to take care of any (delayed) i-cache + * flushing that may be necessary. + */ +extern void lazy_mmu_prot_update (pte_t pte); + +#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS +/* + * Update PTEP with ENTRY, which is guaranteed to be a less + * restrictive PTE. That is, ENTRY may have the ACCESSED, DIRTY, and + * WRITABLE bits turned on, when the value at PTEP did not. The + * WRITABLE bit may only be turned if SAFELY_WRITABLE is TRUE. + * + * SAFELY_WRITABLE is TRUE if we can update the value at PTEP without + * having to worry about races. On SMP machines, there are only two + * cases where this is true: + * + * (1) *PTEP has the PRESENT bit turned OFF + * (2) ENTRY has the DIRTY bit turned ON + * + * On ia64, we could implement this routine with a cmpxchg()-loop + * which ORs in the _PAGE_A/_PAGE_D bit if they're set in ENTRY. + * However, like on x86, we can get a more streamlined version by + * observing that it is OK to drop ACCESSED bit updates when + * SAFELY_WRITABLE is FALSE. Besides being rare, all that would do is + * result in an extra Access-bit fault, which would then turn on the + * ACCESSED bit in the low-level fault handler (iaccess_bit or + * daccess_bit in ivt.S). + */ +#ifdef CONFIG_SMP +# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \ +do { \ + if (__safely_writable) { \ + set_pte(__ptep, __entry); \ + flush_tlb_page(__vma, __addr); \ + } \ +} while (0) +#else +# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \ + ptep_establish(__vma, __addr, __ptep, __entry) +#endif + +# ifdef CONFIG_VIRTUAL_MEM_MAP + /* arch mem_map init routine is needed due to holes in a virtual mem_map */ +# define __HAVE_ARCH_MEMMAP_INIT + extern void memmap_init (unsigned long size, int nid, unsigned long zone, + unsigned long start_pfn); +# endif /* CONFIG_VIRTUAL_MEM_MAP */ +# endif /* !__ASSEMBLY__ */ + +/* + * Identity-mapped regions use a large page size. We'll call such large pages + * "granules". If you can think of a better name that's unambiguous, let me + * know... + */ +#if defined(CONFIG_IA64_GRANULE_64MB) +# define IA64_GRANULE_SHIFT _PAGE_SIZE_64M +#elif defined(CONFIG_IA64_GRANULE_16MB) +# define IA64_GRANULE_SHIFT _PAGE_SIZE_16M +#endif +#define IA64_GRANULE_SIZE (1 << IA64_GRANULE_SHIFT) +/* + * log2() of the page size we use to map the kernel image (IA64_TR_KERNEL): + */ +#define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M +#define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + +/* These tell get_user_pages() that the first gate page is accessible from user-level. */ +#define FIXADDR_USER_START GATE_ADDR +#ifdef HAVE_BUGGY_SEGREL +# define FIXADDR_USER_END (GATE_ADDR + 2*PAGE_SIZE) +#else +# define FIXADDR_USER_END (GATE_ADDR + 2*PERCPU_PAGE_SIZE) +#endif + +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY +#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +#define __HAVE_ARCH_PTEP_SET_WRPROTECT +#define __HAVE_ARCH_PTE_SAME +#define __HAVE_ARCH_PGD_OFFSET_GATE +#define __HAVE_ARCH_LAZY_MMU_PROT_UPDATE + +#include <asm-generic/pgtable-nopud.h> +#include <asm-generic/pgtable.h> + +#endif /* _ASM_IA64_PGTABLE_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm-generic/unaligned.h --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm-generic/unaligned.h Thu Sep 1 18:46:28 2005 @@ -0,0 +1,122 @@ +#ifndef _ASM_GENERIC_UNALIGNED_H_ +#define _ASM_GENERIC_UNALIGNED_H_ + +/* + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. + * + * This is based almost entirely upon Richard Henderson's + * asm-alpha/unaligned.h implementation. Some comments were + * taken from David Mosberger's asm-ia64/unaligned.h header. + */ + +#include <linux/types.h> + +/* + * The main single-value unaligned transfer routines. + */ +#define get_unaligned(ptr) \ + ((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr)))) +#define put_unaligned(x,ptr) \ + __put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr))) + +/* + * This function doesn't actually exist. The idea is that when + * someone uses the macros below with an unsupported size (datatype), + * the linker will alert us to the problem via an unresolved reference + * error. + */ +extern void bad_unaligned_access_length(void) __attribute__((noreturn)); + +struct __una_u64 { __u64 x __attribute__((packed)); }; +struct __una_u32 { __u32 x __attribute__((packed)); }; +struct __una_u16 { __u16 x __attribute__((packed)); }; + +/* + * Elemental unaligned loads + */ + +static inline unsigned long __uldq(const __u64 *addr) +{ + const struct __una_u64 *ptr = (const struct __una_u64 *) addr; + return ptr->x; +} + +static inline unsigned long __uldl(const __u32 *addr) +{ + const struct __una_u32 *ptr = (const struct __una_u32 *) addr; + return ptr->x; +} + +static inline unsigned long __uldw(const __u16 *addr) +{ + const struct __una_u16 *ptr = (const struct __una_u16 *) addr; + return ptr->x; +} + +/* + * Elemental unaligned stores + */ + +static inline void __ustq(__u64 val, __u64 *addr) +{ + struct __una_u64 *ptr = (struct __una_u64 *) addr; + ptr->x = val; +} + +static inline void __ustl(__u32 val, __u32 *addr) +{ + struct __una_u32 *ptr = (struct __una_u32 *) addr; + ptr->x = val; +} + +static inline void __ustw(__u16 val, __u16 *addr) +{ + struct __una_u16 *ptr = (struct __una_u16 *) addr; + ptr->x = val; +} + +#define __get_unaligned(ptr, size) ({ \ + const void *__gu_p = ptr; \ + unsigned long val; \ + switch (size) { \ + case 1: \ + val = *(const __u8 *)__gu_p; \ + break; \ + case 2: \ + val = __uldw(__gu_p); \ + break; \ + case 4: \ + val = __uldl(__gu_p); \ + break; \ + case 8: \ + val = __uldq(__gu_p); \ + break; \ + default: \ + bad_unaligned_access_length(); \ + }; \ + val; \ +}) + +#define __put_unaligned(val, ptr, size) \ +do { \ + void *__gu_p = ptr; \ + switch (size) { \ + case 1: \ + *(__u8 *)__gu_p = val; \ + break; \ + case 2: \ + __ustw(val, __gu_p); \ + break; \ + case 4: \ + __ustl(val, __gu_p); \ + break; \ + case 8: \ + __ustq(val, __gu_p); \ + break; \ + default: \ + bad_unaligned_access_length(); \ + }; \ +} while(0) + +#endif /* _ASM_GENERIC_UNALIGNED_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/numnodes.h --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/asm/numnodes.h Thu Sep 1 18:46:28 2005 @@ -0,0 +1,15 @@ +#ifndef _ASM_MAX_NUMNODES_H +#define _ASM_MAX_NUMNODES_H + +#ifdef CONFIG_IA64_DIG +/* Max 8 Nodes */ +#define NODES_SHIFT 3 +#elif defined(CONFIG_IA64_HP_ZX1) || defined(CONFIG_IA64_HP_ZX1_SWIOTLB) +/* Max 32 Nodes */ +#define NODES_SHIFT 5 +#elif defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC) +/* Max 256 Nodes */ +#define NODES_SHIFT 8 +#endif + +#endif /* _ASM_MAX_NUMNODES_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/time.h --- /dev/null Thu Sep 1 17:09:27 2005 +++ b/xen/include/asm-ia64/linux/time.h Thu Sep 1 18:46:28 2005 @@ -0,0 +1,181 @@ +#ifndef _LINUX_TIME_H +#define _LINUX_TIME_H + +#include <linux/types.h> + +#ifdef __KERNEL__ +#include <linux/seqlock.h> +#endif + +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif /* _STRUCT_TIMESPEC */ + +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#ifdef __KERNEL__ + +/* Parameters used to convert the timespec values */ +#ifndef USEC_PER_SEC +#define USEC_PER_SEC (1000000L) +#endif + +#ifndef NSEC_PER_SEC +#define NSEC_PER_SEC (1000000000L) +#endif + +#ifndef NSEC_PER_USEC +#define NSEC_PER_USEC (1000L) +#endif + +static __inline__ int timespec_equal(struct timespec *a, struct timespec *b) +{ + return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long +mktime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + + return ((( + (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +extern struct timespec xtime; +extern struct timespec wall_to_monotonic; +extern seqlock_t xtime_lock; + +static inline unsigned long get_seconds(void) +{ + return xtime.tv_sec; +} + +struct timespec current_kernel_time(void); + +#define CURRENT_TIME (current_kernel_time()) +#define CURRENT_TIME_SEC ((struct timespec) { xtime.tv_sec, 0 }) + +extern void do_gettimeofday(struct timeval *tv); +extern int do_settimeofday(struct timespec *tv); +extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz); +extern void clock_was_set(void); // call when ever the clock is set +extern int do_posix_clock_monotonic_gettime(struct timespec *tp); +extern long do_nanosleep(struct timespec *t); +extern long do_utimes(char __user * filename, struct timeval * times); +struct itimerval; +extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue); +extern int do_getitimer(int which, struct itimerval *value); +extern void getnstimeofday (struct timespec *tv); + +extern struct timespec timespec_trunc(struct timespec t, unsigned gran); + +static inline void +set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) +{ + while (nsec > NSEC_PER_SEC) { + nsec -= NSEC_PER_SEC; + ++sec; + } + while (nsec < 0) { + nsec += NSEC_PER_SEC; + --sec; + } + ts->tv_sec = sec; + ts->tv_nsec = nsec; +} + +#endif /* __KERNEL__ */ + +#define NFDBITS __NFDBITS + +#define FD_SETSIZE __FD_SETSIZE +#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp) +#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp) +#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp) +#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerspec { + struct timespec it_interval; /* timer period */ + struct timespec it_value; /* timer expiration */ +}; + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + + +/* + * The IDs of the various system clocks (for POSIX.1b interval timers). + */ +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_REALTIME_HR 4 +#define CLOCK_MONOTONIC_HR 5 + +/* + * The IDs of various hardware clocks + */ + + +#define CLOCK_SGI_CYCLE 10 +#define MAX_CLOCKS 16 +#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC | \ + CLOCK_REALTIME_HR | CLOCK_MONOTONIC_HR) +#define CLOCKS_MONO (CLOCK_MONOTONIC & CLOCK_MONOTONIC_HR) + +/* + * The various flags for setting POSIX.1b interval timers. + */ + +#define TIMER_ABSTIME 0x01 + + +#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/acpi.c --- a/xen/arch/ia64/acpi.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,678 +0,0 @@ -/* - * acpi.c - Architecture-Specific Low-Level ACPI Support - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999,2000 Walt Drummond <drummond@xxxxxxxxxxx> - * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co. - * David Mosberger-Tang <davidm@xxxxxxxxxx> - * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@xxxxxxxxx> - * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@xxxxxxxxx> - * Copyright (C) 2001 Jenna Hall <jenna.s.hall@xxxxxxxxx> - * Copyright (C) 2001 Takayoshi Kochi <t-kochi@xxxxxxxxxxxxx> - * Copyright (C) 2002 Erich Focht <efocht@xxxxxxxxxx> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/irq.h> -#include <linux/acpi.h> -#include <linux/efi.h> -#include <linux/mmzone.h> -#include <asm/io.h> -//#include <asm/iosapic.h> -#include <asm/machvec.h> -#include <asm/page.h> -#include <asm/system.h> -#include <asm/numa.h> -#include <asm/sal.h> -//#include <asm/cyclone.h> - -#define BAD_MADT_ENTRY(entry, end) ( \ - (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((acpi_table_entry_header *)entry)->length != sizeof(*entry)) - -#define PREFIX "ACPI: " - -void (*pm_idle) (void); -EXPORT_SYMBOL(pm_idle); -void (*pm_power_off) (void); - -unsigned char acpi_kbd_controller_present = 1; -unsigned char acpi_legacy_devices; - -const char * -acpi_get_sysname (void) -{ -/* #ifdef CONFIG_IA64_GENERIC */ - unsigned long rsdp_phys; - struct acpi20_table_rsdp *rsdp; - struct acpi_table_xsdt *xsdt; - struct acpi_table_header *hdr; - - rsdp_phys = acpi_find_rsdp(); - if (!rsdp_phys) { - printk(KERN_ERR "ACPI 2.0 RSDP not found, default to \"dig\"\n"); - return "dig"; - } - - rsdp = (struct acpi20_table_rsdp *) __va(rsdp_phys); - if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { - printk(KERN_ERR "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); - return "dig"; - } - - xsdt = (struct acpi_table_xsdt *) __va(rsdp->xsdt_address); - hdr = &xsdt->header; - if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { - printk(KERN_ERR "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); - return "dig"; - } - - if (!strcmp(hdr->oem_id, "HP")) { - return "hpzx1"; - } - else if (!strcmp(hdr->oem_id, "SGI")) { - return "sn2"; - } - - return "dig"; -/* -#else -# if defined (CONFIG_IA64_HP_SIM) - return "hpsim"; -# elif defined (CONFIG_IA64_HP_ZX1) - return "hpzx1"; -# elif defined (CONFIG_IA64_SGI_SN2) - return "sn2"; -# elif defined (CONFIG_IA64_DIG) - return "dig"; -# else -# error Unknown platform. Fix acpi.c. -# endif -#endif -*/ -} - -#ifdef CONFIG_ACPI_BOOT - -#define ACPI_MAX_PLATFORM_INTERRUPTS 256 - -#if 0 -/* Array to record platform interrupt vectors for generic interrupt routing. */ -int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { - [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 -}; - -enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC; - -/* - * Interrupt routing API for device drivers. Provides interrupt vector for - * a generic platform event. Currently only CPEI is implemented. - */ -int -acpi_request_vector (u32 int_type) -{ - int vector = -1; - - if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) { - /* corrected platform error interrupt */ - vector = platform_intr_list[int_type]; - } else - printk(KERN_ERR "acpi_request_vector(): invalid interrupt type\n"); - return vector; -} -#endif -char * -__acpi_map_table (unsigned long phys_addr, unsigned long size) -{ - return __va(phys_addr); -} - -/* -------------------------------------------------------------------------- - Boot-time Table Parsing - -------------------------------------------------------------------------- */ - -static int total_cpus __initdata; -static int available_cpus __initdata; -struct acpi_table_madt * acpi_madt __initdata; -static u8 has_8259; - -#if 0 -static int __init -acpi_parse_lapic_addr_ovr ( - acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_lapic_addr_ovr *lapic; - - lapic = (struct acpi_table_lapic_addr_ovr *) header; - - if (BAD_MADT_ENTRY(lapic, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - if (lapic->address) { - iounmap((void *) ipi_base_addr); - ipi_base_addr = (unsigned long) ioremap(lapic->address, 0); - } - return 0; -} - - -static int __init -acpi_parse_lsapic (acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_lsapic *lsapic; - - lsapic = (struct acpi_table_lsapic *) header; - - if (BAD_MADT_ENTRY(lsapic, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - printk(KERN_INFO "CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid); - - if (!lsapic->flags.enabled) - printk(" disabled"); - else { - printk(" enabled"); -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; - if (hard_smp_processor_id() - == (unsigned int) smp_boot_data.cpu_phys_id[available_cpus]) - printk(" (BSP)"); -#endif - ++available_cpus; - } - - printk("\n"); - - total_cpus++; - return 0; -} - - -static int __init -acpi_parse_lapic_nmi (acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_lapic_nmi *lacpi_nmi; - - lacpi_nmi = (struct acpi_table_lapic_nmi*) header; - - if (BAD_MADT_ENTRY(lacpi_nmi, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - /* TBD: Support lapic_nmi entries */ - return 0; -} - - -static int __init -acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_iosapic *iosapic; - - iosapic = (struct acpi_table_iosapic *) header; - - if (BAD_MADT_ENTRY(iosapic, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - iosapic_init(iosapic->address, iosapic->global_irq_base); - - return 0; -} - - -static int __init -acpi_parse_plat_int_src ( - acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_plat_int_src *plintsrc; - int vector; - - plintsrc = (struct acpi_table_plat_int_src *) header; - - if (BAD_MADT_ENTRY(plintsrc, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - /* - * Get vector assignment for this interrupt, set attributes, - * and program the IOSAPIC routing table. - */ - vector = iosapic_register_platform_intr(plintsrc->type, - plintsrc->global_irq, - plintsrc->iosapic_vector, - plintsrc->eid, - plintsrc->id, - (plintsrc->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - (plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); - - platform_intr_list[plintsrc->type] = vector; - return 0; -} - - -static int __init -acpi_parse_int_src_ovr ( - acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_int_src_ovr *p; - - p = (struct acpi_table_int_src_ovr *) header; - - if (BAD_MADT_ENTRY(p, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - iosapic_override_isa_irq(p->bus_irq, p->global_irq, - (p->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - (p->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); - return 0; -} - - -static int __init -acpi_parse_nmi_src (acpi_table_entry_header *header, const unsigned long end) -{ - struct acpi_table_nmi_src *nmi_src; - - nmi_src = (struct acpi_table_nmi_src*) header; - - if (BAD_MADT_ENTRY(nmi_src, end)) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - /* TBD: Support nimsrc entries */ - return 0; -} -/* Hook from generic ACPI tables.c */ -void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - if (!strncmp(oem_id, "IBM", 3) && - (!strncmp(oem_table_id, "SERMOW", 6))){ - - /* Unfortunatly ITC_DRIFT is not yet part of the - * official SAL spec, so the ITC_DRIFT bit is not - * set by the BIOS on this hardware. - */ - sal_platform_features |= IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT; - - /*Start cyclone clock*/ - cyclone_setup(0); - } -} - -static int __init -acpi_parse_madt (unsigned long phys_addr, unsigned long size) -{ - if (!phys_addr || !size) - return -EINVAL; - - acpi_madt = (struct acpi_table_madt *) __va(phys_addr); - - /* remember the value for reference after free_initmem() */ -#ifdef CONFIG_ITANIUM - has_8259 = 1; /* Firmware on old Itanium systems is broken */ -#else - has_8259 = acpi_madt->flags.pcat_compat; -#endif - iosapic_system_init(has_8259); - - /* Get base address of IPI Message Block */ - - if (acpi_madt->lapic_address) - ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0); - - printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr); - - acpi_madt_oem_check(acpi_madt->header.oem_id, - acpi_madt->header.oem_table_id); - - return 0; -} -#endif - -#ifdef CONFIG_ACPI_NUMA - -#undef SLIT_DEBUG - -#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32) - -static int __initdata srat_num_cpus; /* number of cpus */ -static u32 __initdata pxm_flag[PXM_FLAG_LEN]; -#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag)) -#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag)) -/* maps to convert between proximity domain and logical node ID */ -int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS]; -int __initdata nid_to_pxm_map[MAX_NUMNODES]; -static struct acpi_table_slit __initdata *slit_table; - -/* - * ACPI 2.0 SLIT (System Locality Information Table) - * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf - */ -void __init -acpi_numa_slit_init (struct acpi_table_slit *slit) -{ - u32 len; - - len = sizeof(struct acpi_table_header) + 8 - + slit->localities * slit->localities; - if (slit->header.length != len) { - printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", - len, slit->header.length); - memset(numa_slit, 10, sizeof(numa_slit)); - return; - } - slit_table = slit; -} - -void __init -acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa) -{ - /* record this node in proximity bitmap */ - pxm_bit_set(pa->proximity_domain); - - node_cpuid[srat_num_cpus].phys_id = (pa->apic_id << 8) | (pa->lsapic_eid); - /* nid should be overridden as logical node id later */ - node_cpuid[srat_num_cpus].nid = pa->proximity_domain; - srat_num_cpus++; -} - -void __init -acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma) -{ - unsigned long paddr, size; - u8 pxm; - struct node_memblk_s *p, *q, *pend; - - pxm = ma->proximity_domain; - - /* fill node memory chunk structure */ - paddr = ma->base_addr_hi; - paddr = (paddr << 32) | ma->base_addr_lo; - size = ma->length_hi; - size = (size << 32) | ma->length_lo; - - /* Ignore disabled entries */ - if (!ma->flags.enabled) - return; - - /* record this node in proximity bitmap */ - pxm_bit_set(pxm); - - /* Insertion sort based on base address */ - pend = &node_memblk[num_node_memblks]; - for (p = &node_memblk[0]; p < pend; p++) { - if (paddr < p->start_paddr) - break; - } - if (p < pend) { - for (q = pend - 1; q >= p; q--) - *(q + 1) = *q; - } - p->start_paddr = paddr; - p->size = size; - p->nid = pxm; - num_node_memblks++; -} - -void __init -acpi_numa_arch_fixup (void) -{ - int i, j, node_from, node_to; - - /* If there's no SRAT, fix the phys_id */ - if (srat_num_cpus == 0) { - node_cpuid[0].phys_id = hard_smp_processor_id(); - return; - } - - /* calculate total number of nodes in system from PXM bitmap */ - numnodes = 0; /* init total nodes in system */ - - memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map)); - memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map)); - for (i = 0; i < MAX_PXM_DOMAINS; i++) { - if (pxm_bit_test(i)) { - pxm_to_nid_map[i] = numnodes; - node_set_online(numnodes); - nid_to_pxm_map[numnodes++] = i; - } - } - - /* set logical node id in memory chunk structure */ - for (i = 0; i < num_node_memblks; i++) - node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid]; - - /* assign memory bank numbers for each chunk on each node */ - for (i = 0; i < numnodes; i++) { - int bank; - - bank = 0; - for (j = 0; j < num_node_memblks; j++) - if (node_memblk[j].nid == i) - node_memblk[j].bank = bank++; - } - - /* set logical node id in cpu structure */ - for (i = 0; i < srat_num_cpus; i++) - node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid]; - - printk(KERN_INFO "Number of logical nodes in system = %d\n", numnodes); - printk(KERN_INFO "Number of memory chunks in system = %d\n", num_node_memblks); - - if (!slit_table) return; - memset(numa_slit, -1, sizeof(numa_slit)); - for (i=0; i<slit_table->localities; i++) { - if (!pxm_bit_test(i)) - continue; - node_from = pxm_to_nid_map[i]; - for (j=0; j<slit_table->localities; j++) { - if (!pxm_bit_test(j)) - continue; - node_to = pxm_to_nid_map[j]; - node_distance(node_from, node_to) = - slit_table->entry[i*slit_table->localities + j]; - } - } - -#ifdef SLIT_DEBUG - printk("ACPI 2.0 SLIT locality table:\n"); - for (i = 0; i < numnodes; i++) { - for (j = 0; j < numnodes; j++) - printk("%03d ", node_distance(i,j)); - printk("\n"); - } -#endif -} -#endif /* CONFIG_ACPI_NUMA */ - -#if 0 -unsigned int -acpi_register_gsi (u32 gsi, int polarity, int trigger) -{ - return acpi_register_irq(gsi, polarity, trigger); -} -EXPORT_SYMBOL(acpi_register_gsi); -static int __init -acpi_parse_fadt (unsigned long phys_addr, unsigned long size) -{ - struct acpi_table_header *fadt_header; - struct fadt_descriptor_rev2 *fadt; - - if (!phys_addr || !size) - return -EINVAL; - - fadt_header = (struct acpi_table_header *) __va(phys_addr); - if (fadt_header->revision != 3) - return -ENODEV; /* Only deal with ACPI 2.0 FADT */ - - fadt = (struct fadt_descriptor_rev2 *) fadt_header; - - if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER)) - acpi_kbd_controller_present = 0; - - if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES) - acpi_legacy_devices = 1; - - acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE); - return 0; -} -#endif - -unsigned long __init -acpi_find_rsdp (void) -{ - unsigned long rsdp_phys = 0; - - if (efi.acpi20) - rsdp_phys = __pa(efi.acpi20); - else if (efi.acpi) - printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n"); - return rsdp_phys; -} - -#if 0 -int __init -acpi_boot_init (void) -{ - - /* - * MADT - * ---- - * Parse the Multiple APIC Description Table (MADT), if exists. - * Note that this table provides platform SMP configuration - * information -- the successor to MPS tables. - */ - - if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) { - printk(KERN_ERR PREFIX "Can't find MADT\n"); - goto skip_madt; - } - - /* Local APIC */ - - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) - printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - - if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) < 1) - printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); - - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) < 0) - printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); - - /* I/O APIC */ - - if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) - printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); - - /* System-Level Interrupt Routing */ - - if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) - printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); - - if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) - printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - - if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) - printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); - skip_madt: - - /* - * FADT says whether a legacy keyboard controller is present. - * The FADT also contains an SCI_INT line, by which the system - * gets interrupts such as power and sleep buttons. If it's not - * on a Legacy interrupt, it needs to be setup. - */ - if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1) - printk(KERN_ERR PREFIX "Can't find FADT\n"); - -#ifdef CONFIG_SMP - if (available_cpus == 0) { - printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n"); - printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id()); - smp_boot_data.cpu_phys_id[available_cpus] = hard_smp_processor_id(); - available_cpus = 1; /* We've got at least one of these, no? */ - } - smp_boot_data.cpu_count = available_cpus; - - smp_build_cpu_map(); -# ifdef CONFIG_ACPI_NUMA - if (srat_num_cpus == 0) { - int cpu, i = 1; - for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++) - if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id()) - node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu]; - } - build_cpu_to_node_map(); -# endif -#endif - /* Make boot-up look pretty */ - printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus); - return 0; -} -int -acpi_gsi_to_irq (u32 gsi, unsigned int *irq) -{ - int vector; - - if (has_8259 && gsi < 16) - *irq = isa_irq_to_vector(gsi); - else { - vector = gsi_to_vector(gsi); - if (vector == -1) - return -1; - - *irq = vector; - } - return 0; -} - -int -acpi_register_irq (u32 gsi, u32 polarity, u32 trigger) -{ - if (has_8259 && gsi < 16) - return isa_irq_to_vector(gsi); - - return iosapic_register_intr(gsi, - (polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - (trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); -} -EXPORT_SYMBOL(acpi_register_irq); -#endif -#endif /* CONFIG_ACPI_BOOT */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/dom0_ops.c --- a/xen/arch/ia64/dom0_ops.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,237 +0,0 @@ -/****************************************************************************** - * Arch-specific dom0_ops.c - * - * Process command requests from domain-0 guest OS. - * - * Copyright (c) 2002, K A Fraser - */ - -#include <xen/config.h> -#include <xen/types.h> -#include <xen/lib.h> -#include <xen/mm.h> -#include <public/dom0_ops.h> -#include <xen/sched.h> -#include <xen/event.h> -#include <asm/pdb.h> -#include <xen/trace.h> -#include <xen/console.h> -#include <public/sched_ctl.h> - -long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) -{ - long ret = 0; - - if ( !IS_PRIV(current->domain) ) - return -EPERM; - - switch ( op->cmd ) - { - case DOM0_GETPAGEFRAMEINFO: - { - struct pfn_info *page; - unsigned long pfn = op->u.getpageframeinfo.pfn; - domid_t dom = op->u.getpageframeinfo.domain; - struct domain *d; - - ret = -EINVAL; - - if ( unlikely(pfn >= max_page) || - unlikely((d = find_domain_by_id(dom)) == NULL) ) - break; - - page = &frame_table[pfn]; - - if ( likely(get_page(page, d)) ) - { - ret = 0; - - op->u.getpageframeinfo.type = NOTAB; - - if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) - { - switch ( page->u.inuse.type_info & PGT_type_mask ) - { - default: - panic("No such page type\n"); - break; - } - } - - put_page(page); - } - - put_domain(d); - - copy_to_user(u_dom0_op, op, sizeof(*op)); - } - break; - - case DOM0_GETPAGEFRAMEINFO2: - { -#define GPF2_BATCH 128 - int n,j; - int num = op->u.getpageframeinfo2.num; - domid_t dom = op->u.getpageframeinfo2.domain; - unsigned long *s_ptr = (unsigned long*) op->u.getpageframeinfo2.array; - struct domain *d; - unsigned long *l_arr; - ret = -ESRCH; - - if ( unlikely((d = find_domain_by_id(dom)) == NULL) ) - break; - - if ( unlikely(num > 1024) ) - { - ret = -E2BIG; - break; - } - - l_arr = (unsigned long *)alloc_xenheap_page(); - - ret = 0; - for( n = 0; n < num; ) - { - int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n); - - if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) ) - { - ret = -EINVAL; - break; - } - - for( j = 0; j < k; j++ ) - { - struct pfn_info *page; - unsigned long mfn = l_arr[j]; - - if ( unlikely(mfn >= max_page) ) - goto e2_err; - - page = &frame_table[mfn]; - - if ( likely(get_page(page, d)) ) - { - unsigned long type = 0; - - switch( page->u.inuse.type_info & PGT_type_mask ) - { - default: - panic("No such page type\n"); - break; - } - - if ( page->u.inuse.type_info & PGT_pinned ) - type |= LPINTAB; - l_arr[j] |= type; - put_page(page); - } - else - { - e2_err: - l_arr[j] |= XTAB; - } - - } - - if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) ) - { - ret = -EINVAL; - break; - } - - n += j; - } - - free_xenheap_page((unsigned long)l_arr); - - put_domain(d); - } - break; -#ifndef CONFIG_VTI - /* - * NOTE: DOM0_GETMEMLIST has somewhat different semantics on IA64 - - * it actually allocates and maps pages. - */ - case DOM0_GETMEMLIST: - { - unsigned long i; - struct domain *d = find_domain_by_id(op->u.getmemlist.domain); - unsigned long start_page = op->u.getmemlist.max_pfns >> 32; - unsigned long nr_pages = op->u.getmemlist.max_pfns & 0xffffffff; - unsigned long pfn; - unsigned long *buffer = op->u.getmemlist.buffer; - struct page *page; - - ret = -EINVAL; - if ( d != NULL ) - { - ret = 0; - - for ( i = start_page; i < (start_page + nr_pages); i++ ) - { - page = map_new_domain_page(d, i << PAGE_SHIFT); - if ( page == NULL ) - { - ret = -ENOMEM; - break; - } - pfn = page_to_pfn(page); - if ( put_user(pfn, buffer) ) - { - ret = -EFAULT; - break; - } - buffer++; - } - - op->u.getmemlist.num_pfns = i - start_page; - copy_to_user(u_dom0_op, op, sizeof(*op)); - - put_domain(d); - } - } - break; -#else - case DOM0_GETMEMLIST: - { - int i; - struct domain *d = find_domain_by_id(op->u.getmemlist.domain); - unsigned long max_pfns = op->u.getmemlist.max_pfns; - unsigned long pfn; - unsigned long *buffer = op->u.getmemlist.buffer; - struct list_head *list_ent; - - ret = -EINVAL; - if (!d) { - ret = 0; - - spin_lock(&d->page_alloc_lock); - list_ent = d->page_list.next; - for (i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++) { - pfn = list_entry(list_ent, struct pfn_info, list) - - frame_table; - if (put_user(pfn, buffer)) { - ret = -EFAULT; - break; - } - buffer++; - list_ent = frame_table[pfn].list.next; - } - spin_unlock(&d->page_alloc_lock); - - op->u.getmemlist.num_pfns = i; - copy_to_user(u_dom0_op, op, sizeof(*op)); - - put_domain(d); - } - } - break; -#endif // CONFIG_VTI - default: - ret = -ENOSYS; - - } - - return ret; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/dom_fw.c --- a/xen/arch/ia64/dom_fw.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,688 +0,0 @@ -/* - * Xen domain firmware emulation support - * Copyright (C) 2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <xen/config.h> -#include <asm/system.h> -#include <asm/pgalloc.h> - -#include <linux/efi.h> -#include <asm/io.h> -#include <asm/pal.h> -#include <asm/sal.h> -#include <xen/acpi.h> - -#include <asm/dom_fw.h> - -struct ia64_boot_param *dom_fw_init(struct domain *, char *,int,char *,int); -extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); -extern struct domain *dom0; -extern unsigned long dom0_start; - -extern unsigned long running_on_sim; - - -unsigned long dom_fw_base_mpa = -1; -unsigned long imva_fw_base = -1; - -// return domain (meta)physical address for a given imva -// this function is a call-back from dom_fw_init -unsigned long dom_pa(unsigned long imva) -{ - if (dom_fw_base_mpa == -1 || imva_fw_base == -1) { - printf("dom_pa: uninitialized! (spinning...)\n"); - while(1); - } - if (imva - imva_fw_base > PAGE_SIZE) { - printf("dom_pa: bad offset! imva=%p, imva_fw_base=%p (spinning...)\n",imva,imva_fw_base); - while(1); - } - return dom_fw_base_mpa + (imva - imva_fw_base); -} - -// builds a hypercall bundle at domain physical address -void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall) -{ - unsigned long imva; - - if (d == dom0) paddr += dom0_start; - imva = domain_mpa_to_imva(d,paddr); - build_hypercall_bundle(imva,d->arch.breakimm,hypercall,1); -} - - -// builds a hypercall bundle at domain physical address -void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret) -{ - unsigned long imva; - - if (d == dom0) paddr += dom0_start; - imva = domain_mpa_to_imva(d,paddr); - build_hypercall_bundle(imva,d->arch.breakimm,hypercall,ret); -} - - -// FIXME: This is really a hack: Forcing the boot parameter block -// at domain mpaddr 0 page, then grabbing only the low bits of the -// Xen imva, which is the offset into the page -unsigned long dom_fw_setup(struct domain *d, char *args, int arglen) -{ - struct ia64_boot_param *bp; - - dom_fw_base_mpa = 0; - if (d == dom0) dom_fw_base_mpa += dom0_start; - imva_fw_base = domain_mpa_to_imva(d,dom_fw_base_mpa); - bp = dom_fw_init(d,args,arglen,imva_fw_base,PAGE_SIZE); - return dom_pa((unsigned long)bp); -} - - -/* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */ - -#define MB (1024*1024UL) - -#define NUM_EFI_SYS_TABLES 6 -#define PASS_THRU_IOPORT_SPACE -#ifdef PASS_THRU_IOPORT_SPACE -# define NUM_MEM_DESCS 4 -#else -# define NUM_MEM_DESCS 3 -#endif - - -#define SECS_PER_HOUR (60 * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -/* Compute the `struct tm' representation of *T, - offset OFFSET seconds east of UTC, - and store year, yday, mon, mday, wday, hour, min, sec into *TP. - Return nonzero if successful. */ -int -offtime (unsigned long t, efi_time_t *tp) -{ - const unsigned short int __mon_yday[2][13] = - { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - long int days, rem, y; - const unsigned short int *ip; - - days = t / SECS_PER_DAY; - rem = t % SECS_PER_DAY; - while (rem < 0) { - rem += SECS_PER_DAY; - --days; - } - while (rem >= SECS_PER_DAY) { - rem -= SECS_PER_DAY; - ++days; - } - tp->hour = rem / SECS_PER_HOUR; - rem %= SECS_PER_HOUR; - tp->minute = rem / 60; - tp->second = rem % 60; - /* January 1, 1970 was a Thursday. */ - y = 1970; - -# define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -# define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) -# define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - - while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { - /* Guess a corrected year, assuming 365 days per year. */ - long int yg = y + days / 365 - (days % 365 < 0); - - /* Adjust DAYS and Y to match the guessed year. */ - days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - y = yg; - } - tp->year = y; - ip = __mon_yday[__isleap(y)]; - for (y = 11; days < (long int) ip[y]; --y) - continue; - days -= ip[y]; - tp->month = y + 1; - tp->day = days + 1; - return 1; -} - -extern struct ia64_pal_retval pal_emulator_static (unsigned long); - -/* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ - -#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) - -#define REG_OFFSET(addr) (0x00000000000000FF & (addr)) -#define DEVICE_FUNCTION(addr) (0x000000000000FF00 & (addr)) -#define BUS_NUMBER(addr) (0x0000000000FF0000 & (addr)) - -#ifndef XEN -static efi_status_t -fw_efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) -{ -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) - struct { - int tv_sec; /* must be 32bits to work */ - int tv_usec; - } tv32bits; - - ssc((unsigned long) &tv32bits, 0, 0, 0, SSC_GET_TOD); - - memset(tm, 0, sizeof(*tm)); - offtime(tv32bits.tv_sec, tm); - - if (tc) - memset(tc, 0, sizeof(*tc)); -#else -# error Not implemented yet... -#endif - return EFI_SUCCESS; -} - -static void -efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) -{ -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) - ssc(status, 0, 0, 0, SSC_EXIT); -#else -# error Not implemented yet... -#endif -} - -static efi_status_t -efi_unimplemented (void) -{ - return EFI_UNSUPPORTED; -} -#endif /* !XEN */ - -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) -{ - long r9 = 0; - long r10 = 0; - long r11 = 0; - long status; - - /* - * Don't do a "switch" here since that gives us code that - * isn't self-relocatable. - */ - status = 0; - if (index == SAL_FREQ_BASE) { - if (!running_on_sim) - status = ia64_sal_freq_base(in1,&r9,&r10); - else switch (in1) { - case SAL_FREQ_BASE_PLATFORM: - r9 = 200000000; - break; - - case SAL_FREQ_BASE_INTERVAL_TIMER: - r9 = 700000000; - break; - - case SAL_FREQ_BASE_REALTIME_CLOCK: - r9 = 1; - break; - - default: - status = -1; - break; - } - } else if (index == SAL_PCI_CONFIG_READ) { - if (current->domain == dom0) { - u64 value; - // note that args 2&3 are swapped!! - status = ia64_sal_pci_config_read(in1,in3,in2,&value); - r9 = value; - } - else printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n"); - } else if (index == SAL_PCI_CONFIG_WRITE) { - if (current->domain == dom0) { - if (((in1 & ~0xffffffffUL) && (in4 == 0)) || - (in4 > 1) || - (in2 > 8) || (in2 & (in2-1))) - printf("*** SAL_PCI_CONF_WRITE?!?(adr=%p,typ=%p,sz=%p,val=%p)\n",in1,in4,in2,in3); - // note that args are in a different order!! - status = ia64_sal_pci_config_write(in1,in4,in2,in3); - } - else printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); - } else if (index == SAL_SET_VECTORS) { - printf("*** CALLED SAL_SET_VECTORS. IGNORED...\n"); - } else if (index == SAL_GET_STATE_INFO) { - printf("*** CALLED SAL_GET_STATE_INFO. IGNORED...\n"); - } else if (index == SAL_GET_STATE_INFO_SIZE) { - printf("*** CALLED SAL_GET_STATE_INFO_SIZE. IGNORED...\n"); - } else if (index == SAL_CLEAR_STATE_INFO) { - printf("*** CALLED SAL_CLEAR_STATE_INFO. IGNORED...\n"); - } else if (index == SAL_MC_RENDEZ) { - printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); - } else if (index == SAL_MC_SET_PARAMS) { - printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); - } else if (index == SAL_CACHE_FLUSH) { - printf("*** CALLED SAL_CACHE_FLUSH. IGNORED...\n"); - } else if (index == SAL_CACHE_INIT) { - printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n"); - } else if (index == SAL_UPDATE_PAL) { - printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n"); - } else { - printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n"); - status = -1; - } - return ((struct sal_ret_values) {status, r9, r10, r11}); -} - -struct ia64_pal_retval -xen_pal_emulator(unsigned long index, unsigned long in1, - unsigned long in2, unsigned long in3) -{ - long r9 = 0; - long r10 = 0; - long r11 = 0; - long status = -1; - -#define USE_PAL_EMULATOR -#ifdef USE_PAL_EMULATOR - return pal_emulator_static(index); -#endif - if (running_on_sim) return pal_emulator_static(index); - if (index >= PAL_COPY_PAL) { - printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", - index); - } - else switch (index) { - case PAL_MEM_ATTRIB: - status = ia64_pal_mem_attrib(&r9); - break; - case PAL_FREQ_BASE: - status = ia64_pal_freq_base(&r9); - break; - case PAL_PROC_GET_FEATURES: - status = ia64_pal_proc_get_features(&r9,&r10,&r11); - break; - case PAL_BUS_GET_FEATURES: - status = ia64_pal_bus_get_features(&r9,&r10,&r11); - break; - case PAL_FREQ_RATIOS: - status = ia64_pal_freq_ratios(&r9,&r10,&r11); - break; - case PAL_PTCE_INFO: - { - // return hard-coded xen-specific values because ptc.e - // is emulated on xen to always flush everything - // these values result in only one ptc.e instruction - status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0; - } - break; - case PAL_VERSION: - status = ia64_pal_version(&r9,&r10); - break; - case PAL_VM_PAGE_SIZE: - status = ia64_pal_vm_page_size(&r9,&r10); - break; - case PAL_DEBUG_INFO: - status = ia64_pal_debug_info(&r9,&r10); - break; - case PAL_CACHE_SUMMARY: - status = ia64_pal_cache_summary(&r9,&r10); - break; - case PAL_VM_SUMMARY: - // FIXME: what should xen return for these, figure out later - // For now, linux does the right thing if pal call fails - // In particular, rid_size must be set properly! - //status = ia64_pal_vm_summary(&r9,&r10); - break; - case PAL_RSE_INFO: - status = ia64_pal_rse_info(&r9,&r10); - break; - case PAL_VM_INFO: - status = ia64_pal_vm_info(in1,in2,&r9,&r10); - break; - case PAL_REGISTER_INFO: - status = ia64_pal_register_info(in1,&r9,&r10); - break; - case PAL_CACHE_FLUSH: - /* FIXME */ - printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); - BUG(); - break; - case PAL_PERF_MON_INFO: - { - unsigned long pm_buffer[16]; - int i; - status = ia64_pal_perf_mon_info(pm_buffer,&r9); - if (status != 0) { - while(1) - printk("PAL_PERF_MON_INFO fails ret=%d\n",status); - break; - } - if (copy_to_user((void __user *)in1,pm_buffer,128)) { - while(1) - printk("xen_pal_emulator: PAL_PERF_MON_INFO " - "can't copy to user!!!!\n"); - status = -1; - break; - } - } - break; - case PAL_CACHE_INFO: - { - pal_cache_config_info_t ci; - status = ia64_pal_cache_config_info(in1,in2,&ci); - if (status != 0) break; - r9 = ci.pcci_info_1.pcci1_data; - r10 = ci.pcci_info_2.pcci2_data; - } - break; - case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ - printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n"); - break; - case PAL_HALT_INFO: /* inappropriate info for guest? */ - printk("PAL_HALT_INFO NOT IMPLEMENTED, IGNORED!\n"); - break; - default: - printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", - index); - break; - } - return ((struct ia64_pal_retval) {status, r9, r10, r11}); -} - -#define NFUNCPTRS 20 - -void print_md(efi_memory_desc_t *md) -{ -#if 1 - printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", - md->type, md->attribute, md->phys_addr, - md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), - md->num_pages >> (20 - EFI_PAGE_SHIFT)); -#endif -} - -#define LSAPIC_NUM 16 // TEMP -static u32 lsapic_flag=1; - -/* Provide only one LP to guest */ -static int -acpi_update_lsapic (acpi_table_entry_header *header) -{ - struct acpi_table_lsapic *lsapic; - - lsapic = (struct acpi_table_lsapic *) header; - if (!lsapic) - return -EINVAL; - - if (lsapic->flags.enabled && lsapic_flag) { - printk("enable lsapic entry: 0x%lx\n", (u64)lsapic); - lsapic_flag = 0; /* disable all the following processros */ - } else if (lsapic->flags.enabled) { - printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic); - lsapic->flags.enabled = 0; - } else - printk("lsapic entry is already disabled: 0x%lx\n", (u64)lsapic); - - return 0; -} - -static int -acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size) -{ - u8 checksum=0; - u8* ptr; - int len; - struct acpi_table_madt* acpi_madt; - - if (!phys_addr || !size) - return -EINVAL; - - acpi_madt = (struct acpi_table_madt *) __va(phys_addr); - acpi_madt->header.checksum=0; - - /* re-calculate MADT checksum */ - ptr = (u8*)acpi_madt; - len = acpi_madt->header.length; - while (len>0){ - checksum = (u8)( checksum + (*ptr++) ); - len--; - } - acpi_madt->header.checksum = 0x0 - checksum; - - return 0; -} - -/* base is physical address of acpi table */ -void touch_acpi_table(void) -{ - u64 count = 0; - count = acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, NR_CPUS); - if ( count < 1) - printk("Error parsing MADT - no LAPIC entires\n"); - printk("Total %d lsapic entry\n", count); - acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum); - - return; -} - - -struct ia64_boot_param * -dom_fw_init (struct domain *d, char *args, int arglen, char *fw_mem, int fw_mem_size) -{ - efi_system_table_t *efi_systab; - efi_runtime_services_t *efi_runtime; - efi_config_table_t *efi_tables; - struct ia64_sal_systab *sal_systab; - efi_memory_desc_t *efi_memmap, *md; - unsigned long *pal_desc, *sal_desc; - struct ia64_sal_desc_entry_point *sal_ed; - struct ia64_boot_param *bp; - unsigned long *pfn; - unsigned char checksum = 0; - char *cp, *cmd_line, *fw_vendor; - int i = 0; - unsigned long maxmem = d->max_pages * PAGE_SIZE; - unsigned long start_mpaddr = ((d==dom0)?dom0_start:0); - -# define MAKE_MD(typ, attr, start, end, abs) \ - do { \ - md = efi_memmap + i++; \ - md->type = typ; \ - md->pad = 0; \ - md->phys_addr = abs ? start : start_mpaddr + start; \ - md->virt_addr = 0; \ - md->num_pages = (end - start) >> 12; \ - md->attribute = attr; \ - print_md(md); \ - } while (0) - -/* FIXME: should check size but for now we have a whole MB to play with. - And if stealing code from fw-emu.c, watch out for new fw_vendor on the end! - if (fw_mem_size < sizeof(fw_mem_proto)) { - printf("sys_fw_init: insufficient space for fw_mem\n"); - return 0; - } -*/ - memset(fw_mem, 0, fw_mem_size); - -#ifdef XEN -#else - pal_desc = (unsigned long *) &pal_emulator_static; - sal_desc = (unsigned long *) &sal_emulator; -#endif - - cp = fw_mem; - efi_systab = (void *) cp; cp += sizeof(*efi_systab); - efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); - efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables); - sal_systab = (void *) cp; cp += sizeof(*sal_systab); - sal_ed = (void *) cp; cp += sizeof(*sal_ed); - efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); - bp = (void *) cp; cp += sizeof(*bp); - pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn); - cmd_line = (void *) cp; - - if (args) { - if (arglen >= 1024) - arglen = 1023; - memcpy(cmd_line, args, arglen); - } else { - arglen = 0; - } - cmd_line[arglen] = '\0'; - - memset(efi_systab, 0, sizeof(efi_systab)); - efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; - efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; - efi_systab->hdr.headersize = sizeof(efi_systab->hdr); - cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary -#define FW_VENDOR "X\0e\0n\0/\0i\0a\0\066\0\064\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary - - memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR)); - efi_systab->fw_vendor = dom_pa(fw_vendor); - - efi_systab->fw_revision = 1; - efi_systab->runtime = (void *) dom_pa(efi_runtime); - efi_systab->nr_tables = NUM_EFI_SYS_TABLES; - efi_systab->tables = dom_pa(efi_tables); - - efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; - efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; - efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); -#define EFI_HYPERCALL_PATCH(tgt,call) do { \ - dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \ - tgt = dom_pa(pfn); \ - *pfn++ = FW_HYPERCALL_##call##_PADDR + ((d==dom0)?dom0_start:0); \ - *pfn++ = 0; \ - } while (0) - - EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME); - EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME); - EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME); - EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME); - EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP); - EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE); - EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE); - EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE); - EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT); - EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM); - - efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID; - efi_tables[0].table = dom_pa(sal_systab); - for (i = 1; i < NUM_EFI_SYS_TABLES; i++) { - efi_tables[i].guid = NULL_GUID; - efi_tables[i].table = 0; - } - if (d == dom0) { - printf("Domain0 EFI passthrough:"); - i = 1; - if (efi.mps) { - efi_tables[i].guid = MPS_TABLE_GUID; - efi_tables[i].table = __pa(efi.mps); - printf(" MPS=%0xlx",efi_tables[i].table); - i++; - } - - touch_acpi_table(); - - if (efi.acpi20) { - efi_tables[i].guid = ACPI_20_TABLE_GUID; - efi_tables[i].table = __pa(efi.acpi20); - printf(" ACPI 2.0=%0xlx",efi_tables[i].table); - i++; - } - if (efi.acpi) { - efi_tables[i].guid = ACPI_TABLE_GUID; - efi_tables[i].table = __pa(efi.acpi); - printf(" ACPI=%0xlx",efi_tables[i].table); - i++; - } - if (efi.smbios) { - efi_tables[i].guid = SMBIOS_TABLE_GUID; - efi_tables[i].table = __pa(efi.smbios); - printf(" SMBIOS=%0xlx",efi_tables[i].table); - i++; - } - if (efi.hcdp) { - efi_tables[i].guid = HCDP_TABLE_GUID; - efi_tables[i].table = __pa(efi.hcdp); - printf(" HCDP=%0xlx",efi_tables[i].table); - i++; - } - printf("\n"); - } - - /* fill in the SAL system table: */ - memcpy(sal_systab->signature, "SST_", 4); - sal_systab->size = sizeof(*sal_systab); - sal_systab->sal_rev_minor = 1; - sal_systab->sal_rev_major = 0; - sal_systab->entry_count = 1; - - strcpy(sal_systab->oem_id, "Xen/ia64"); - strcpy(sal_systab->product_id, "Xen/ia64"); - - /* fill in an entry point: */ - sal_ed->type = SAL_DESC_ENTRY_POINT; -#define FW_HYPERCALL_PATCH(tgt,call,ret) do { \ - dom_fw_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call,ret); \ - tgt = FW_HYPERCALL_##call##_PADDR + ((d==dom0)?dom0_start:0); \ - } while (0) - FW_HYPERCALL_PATCH(sal_ed->pal_proc,PAL_CALL,0); - FW_HYPERCALL_PATCH(sal_ed->sal_proc,SAL_CALL,1); - sal_ed->gp = 0; // will be ignored - - for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) - checksum += *cp; - - sal_systab->checksum = -checksum; - - /* simulate 1MB free memory at physical address zero */ - i = 0; - MAKE_MD(EFI_BOOT_SERVICES_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0); - /* hypercall patches live here, masquerade as reserved PAL memory */ - MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0); - MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 0); -#ifdef PASS_THRU_IOPORT_SPACE - if (d == dom0 && !running_on_sim) { - /* pass through the I/O port space */ - efi_memory_desc_t *efi_get_io_md(void); - efi_memory_desc_t *ia64_efi_io_md = efi_get_io_md(); - u32 type; - u64 iostart, ioend, ioattr; - - type = ia64_efi_io_md->type; - iostart = ia64_efi_io_md->phys_addr; - ioend = ia64_efi_io_md->phys_addr + - (ia64_efi_io_md->num_pages << 12); - ioattr = ia64_efi_io_md->attribute; - MAKE_MD(type,ioattr,iostart,ioend, 1); - } - else - MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0); -#endif - - bp->efi_systab = dom_pa(fw_mem); - bp->efi_memmap = dom_pa(efi_memmap); - bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); - bp->efi_memdesc_size = sizeof(efi_memory_desc_t); - bp->efi_memdesc_version = 1; - bp->command_line = dom_pa(cmd_line); - bp->console_info.num_cols = 80; - bp->console_info.num_rows = 25; - bp->console_info.orig_x = 0; - bp->console_info.orig_y = 24; - bp->fpswa = 0; - - return bp; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/domain.c --- a/xen/arch/ia64/domain.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1103 +0,0 @@ -/* - * Copyright (C) 1995 Linus Torvalds - * - * Pentium III FXSR, SSE support - * Gareth Hughes <gareth@xxxxxxxxxxx>, May 2000 - * - * Copyright (C) 2005 Intel Co - * Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> - * - * 05/04/29 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> Add CONFIG_VTI domain support - */ - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/errno.h> -#include <xen/sched.h> -#include <xen/smp.h> -#include <xen/delay.h> -#include <xen/softirq.h> -#include <xen/mm.h> -#include <asm/ptrace.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/desc.h> -//#include <asm/mpspec.h> -#include <xen/irq.h> -#include <xen/event.h> -//#include <xen/shadow.h> -#include <xen/console.h> - -#include <xen/elf.h> -//#include <asm/page.h> -#include <asm/pgalloc.h> -#include <asm/dma.h> /* for MAX_DMA_ADDRESS */ - -#include <asm/asm-offsets.h> /* for IA64_THREAD_INFO_SIZE */ - -#include <asm/vcpu.h> /* for function declarations */ -#include <public/arch-ia64.h> -#include <asm/vmx.h> -#include <asm/vmx_vcpu.h> -#include <asm/vmx_vpd.h> -#include <asm/pal.h> -#include <public/io/ioreq.h> - -#define CONFIG_DOMAIN0_CONTIGUOUS -unsigned long dom0_start = -1L; -unsigned long dom0_size = 512*1024*1024; //FIXME: Should be configurable -//FIXME: alignment should be 256MB, lest Linux use a 256MB page size -unsigned long dom0_align = 256*1024*1024; -#ifdef DOMU_BUILD_STAGING -unsigned long domU_staging_size = 32*1024*1024; //FIXME: Should be configurable -unsigned long domU_staging_start; -unsigned long domU_staging_align = 64*1024; -unsigned long *domU_staging_area; -#endif - -// initialized by arch/ia64/setup.c:find_initrd() -unsigned long initrd_start = 0, initrd_end = 0; - -#define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend)) - -//extern int loadelfimage(char *); -extern int readelfimage_base_and_size(char *, unsigned long, - unsigned long *, unsigned long *, unsigned long *); - -unsigned long map_domain_page0(struct domain *); -extern unsigned long dom_fw_setup(struct domain *, char *, int); - -/* this belongs in include/asm, but there doesn't seem to be a suitable place */ -void free_perdomain_pt(struct domain *d) -{ - printf("free_perdomain_pt: not implemented\n"); - //free_page((unsigned long)d->mm.perdomain_pt); -} - -int hlt_counter; - -void disable_hlt(void) -{ - hlt_counter++; -} - -void enable_hlt(void) -{ - hlt_counter--; -} - -static void default_idle(void) -{ - if ( hlt_counter == 0 ) - { - local_irq_disable(); - if ( !softirq_pending(smp_processor_id()) ) - safe_halt(); - //else - local_irq_enable(); - } -} - -void continue_cpu_idle_loop(void) -{ - int cpu = smp_processor_id(); - for ( ; ; ) - { -#ifdef IA64 -// __IRQ_STAT(cpu, idle_timestamp) = jiffies -#else - irq_stat[cpu].idle_timestamp = jiffies; -#endif - while ( !softirq_pending(cpu) ) - default_idle(); - raise_softirq(SCHEDULE_SOFTIRQ); - do_softirq(); - } -} - -void startup_cpu_idle_loop(void) -{ - /* Just some sanity to ensure that the scheduler is set up okay. */ - ASSERT(current->domain == IDLE_DOMAIN_ID); - raise_softirq(SCHEDULE_SOFTIRQ); - do_softirq(); - - /* - * Declares CPU setup done to the boot processor. - * Therefore memory barrier to ensure state is visible. - */ - smp_mb(); -#if 0 -//do we have to ensure the idle task has a shared page so that, for example, -//region registers can be loaded from it. Apparently not... - idle0_task.shared_info = (void *)alloc_xenheap_page(); - memset(idle0_task.shared_info, 0, PAGE_SIZE); - /* pin mapping */ - // FIXME: Does this belong here? Or do only at domain switch time? - { - /* WARNING: following must be inlined to avoid nested fault */ - unsigned long psr = ia64_clear_ic(); - ia64_itr(0x2, IA64_TR_SHARED_INFO, SHAREDINFO_ADDR, - pte_val(pfn_pte(ia64_tpa(idle0_task.shared_info) >> PAGE_SHIFT, PAGE_KERNEL)), - PAGE_SHIFT); - ia64_set_psr(psr); - ia64_srlz_i(); - } -#endif - - continue_cpu_idle_loop(); -} - -struct vcpu *arch_alloc_vcpu_struct(void) -{ - /* Per-vp stack is used here. So we need keep vcpu - * same page as per-vp stack */ - return alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER); -} - -void arch_free_vcpu_struct(struct vcpu *v) -{ - free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); -} - -static void init_switch_stack(struct vcpu *v) -{ - struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; - struct switch_stack *sw = (struct switch_stack *) regs - 1; - extern void ia64_ret_from_clone; - - memset(sw, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); - sw->ar_bspstore = (unsigned long)v + IA64_RBS_OFFSET; - sw->b0 = (unsigned long) &ia64_ret_from_clone; - sw->ar_fpsr = FPSR_DEFAULT; - v->arch._thread.ksp = (unsigned long) sw - 16; - // stay on kernel stack because may get interrupts! - // ia64_ret_from_clone (which b0 gets in new_thread) switches - // to user stack - v->arch._thread.on_ustack = 0; - memset(v->arch._thread.fph,0,sizeof(struct ia64_fpreg)*96); -} - -void arch_do_createdomain(struct vcpu *v) -{ - struct domain *d = v->domain; - struct thread_info *ti = alloc_thread_info(v); - - /* Clear thread_info to clear some important fields, like preempt_count */ - memset(ti, 0, sizeof(struct thread_info)); - init_switch_stack(v); - - d->shared_info = (void *)alloc_xenheap_page(); - if (!d->shared_info) { - printk("ERROR/HALTING: CAN'T ALLOC PAGE\n"); - while (1); - } - memset(d->shared_info, 0, PAGE_SIZE); - d->shared_info->vcpu_data[0].arch.privregs = - alloc_xenheap_pages(get_order(sizeof(mapped_regs_t))); - printf("arch_vcpu_info=%p\n", d->shared_info->vcpu_data[0].arch.privregs); - memset(d->shared_info->vcpu_data[0].arch.privregs, 0, PAGE_SIZE); - v->vcpu_info = &(d->shared_info->vcpu_data[0]); - - d->max_pages = (128UL*1024*1024)/PAGE_SIZE; // 128MB default // FIXME - -#ifdef CONFIG_VTI - /* Per-domain vTLB and vhpt implementation. Now vmx domain will stick - * to this solution. Maybe it can be deferred until we know created - * one as vmx domain */ - v->arch.vtlb = init_domain_tlb(v); -#endif - - /* We may also need emulation rid for region4, though it's unlikely - * to see guest issue uncacheable access in metaphysical mode. But - * keep such info here may be more sane. - */ - if (((d->arch.metaphysical_rr0 = allocate_metaphysical_rr()) == -1UL) - || ((d->arch.metaphysical_rr4 = allocate_metaphysical_rr()) == -1UL)) - BUG(); - VCPU(v, metaphysical_mode) = 1; - v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0; - v->arch.metaphysical_rr4 = d->arch.metaphysical_rr4; - v->arch.metaphysical_saved_rr0 = d->arch.metaphysical_rr0; - v->arch.metaphysical_saved_rr4 = d->arch.metaphysical_rr4; -#define DOMAIN_RID_BITS_DEFAULT 18 - if (!allocate_rid_range(d,DOMAIN_RID_BITS_DEFAULT)) // FIXME - BUG(); - v->arch.starting_rid = d->arch.starting_rid; - v->arch.ending_rid = d->arch.ending_rid; - // the following will eventually need to be negotiated dynamically - d->xen_vastart = XEN_START_ADDR; - d->xen_vaend = XEN_END_ADDR; - d->shared_info_va = SHAREDINFO_ADDR; - d->arch.breakimm = 0x1000; - v->arch.breakimm = d->arch.breakimm; - - d->arch.mm = xmalloc(struct mm_struct); - if (unlikely(!d->arch.mm)) { - printk("Can't allocate mm_struct for domain %d\n",d->domain_id); - return -ENOMEM; - } - memset(d->arch.mm, 0, sizeof(*d->arch.mm)); - d->arch.mm->pgd = pgd_alloc(d->arch.mm); - if (unlikely(!d->arch.mm->pgd)) { - printk("Can't allocate pgd for domain %d\n",d->domain_id); - return -ENOMEM; - } -} - -void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) -{ - struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; - - printf("arch_getdomaininfo_ctxt\n"); - c->regs = *regs; - c->vcpu.evtchn_vector = v->vcpu_info->arch.evtchn_vector; -#if 0 - if (c->vcpu.privregs && copy_to_user(c->vcpu.privregs, - v->vcpu_info->arch.privregs, sizeof(mapped_regs_t))) { - printk("Bad ctxt address: 0x%lx\n", c->vcpu.privregs); - return -EFAULT; - } -#endif - - c->shared = v->domain->shared_info->arch; -} - -int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) -{ - struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; - struct domain *d = v->domain; - int i, rc, ret; - unsigned long progress = 0; - - printf("arch_set_info_guest\n"); - if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) - return 0; - - if (c->flags & VGCF_VMX_GUEST) { - if (!vmx_enabled) { - printk("No VMX hardware feature for vmx domain.\n"); - return -EINVAL; - } - - vmx_setup_platform(v, c); - } - - *regs = c->regs; - new_thread(v, regs->cr_iip, 0, 0); - - v->vcpu_info->arch.evtchn_vector = c->vcpu.evtchn_vector; - if ( c->vcpu.privregs && copy_from_user(v->vcpu_info->arch.privregs, - c->vcpu.privregs, sizeof(mapped_regs_t))) { - printk("Bad ctxt address in arch_set_info_guest: 0x%lx\n", c->vcpu.privregs); - return -EFAULT; - } - - v->arch.domain_itm_last = -1L; - d->shared_info->arch = c->shared; - - /* Don't redo final setup */ - set_bit(_VCPUF_initialised, &v->vcpu_flags); - return 0; -} - -void arch_do_boot_vcpu(struct vcpu *v) -{ - struct domain *d = v->domain; - printf("arch_do_boot_vcpu: not implemented\n"); - - d->shared_info->vcpu_data[v->vcpu_id].arch.privregs = - alloc_xenheap_pages(get_order(sizeof(mapped_regs_t))); - printf("arch_vcpu_info=%p\n", d->shared_info->vcpu_data[v->vcpu_id].arch.privregs); - memset(d->shared_info->vcpu_data[v->vcpu_id].arch.privregs, 0, PAGE_SIZE); - return; -} - -void domain_relinquish_resources(struct domain *d) -{ - /* FIXME */ - printf("domain_relinquish_resources: not implemented\n"); -} - -// heavily leveraged from linux/arch/ia64/kernel/process.c:copy_thread() -// and linux/arch/ia64/kernel/process.c:kernel_thread() -void new_thread(struct vcpu *v, - unsigned long start_pc, - unsigned long start_stack, - unsigned long start_info) -{ - struct domain *d = v->domain; - struct pt_regs *regs; - struct ia64_boot_param *bp; - extern char saved_command_line[]; - - -#ifdef CONFIG_DOMAIN0_CONTIGUOUS - if (d == dom0) start_pc += dom0_start; -#endif - - regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; - if (VMX_DOMAIN(v)) { - /* dt/rt/it:1;i/ic:1, si:1, vm/bn:1, ac:1 */ - regs->cr_ipsr = 0x501008826008; /* Need to be expanded as macro */ - } else { - regs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) - | IA64_PSR_BITS_TO_SET | IA64_PSR_BN - & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS); - regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT; // domain runs at PL2 - } - regs->cr_iip = start_pc; - regs->cr_ifs = 1UL << 63; /* or clear? */ - regs->ar_fpsr = FPSR_DEFAULT; - - if (VMX_DOMAIN(v)) { -#ifdef CONFIG_VTI - vmx_init_all_rr(v); - if (d == dom0) - VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); - /* Virtual processor context setup */ - VMX_VPD(v, vpsr) = IA64_PSR_BN; - VPD_CR(v, dcr) = 0; -#endif - } else { - init_all_rr(v); - if (d == dom0) - regs->r28 = dom_fw_setup(d,saved_command_line,256L); - else { - regs->ar_rsc |= (2 << 2); /* force PL2/3 */ - regs->r28 = dom_fw_setup(d,"nomca nosmp xencons=tty0 console=tty0 root=/dev/hda1",256L); //FIXME - } - VCPU(v, banknum) = 1; - VCPU(v, metaphysical_mode) = 1; - d->shared_info->arch.flags = (d == dom0) ? (SIF_INITDOMAIN|SIF_PRIVILEGED|SIF_BLK_BE_DOMAIN|SIF_NET_BE_DOMAIN|SIF_USB_BE_DOMAIN) : 0; - } -} - -static struct page * map_new_domain0_page(unsigned long mpaddr) -{ - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - printk("map_new_domain0_page: bad domain0 mpaddr %p!\n",mpaddr); -printk("map_new_domain0_page: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size); - while(1); - } - return pfn_to_page((mpaddr >> PAGE_SHIFT)); -} - -/* allocate new page for domain and map it to the specified metaphysical addr */ -struct page * map_new_domain_page(struct domain *d, unsigned long mpaddr) -{ - struct mm_struct *mm = d->arch.mm; - struct page *p = (struct page *)0; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; -extern unsigned long vhpt_paddr, vhpt_pend; - - if (!mm->pgd) { - printk("map_new_domain_page: domain pgd must exist!\n"); - return(p); - } - pgd = pgd_offset(mm,mpaddr); - if (pgd_none(*pgd)) - pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); - - pud = pud_offset(pgd, mpaddr); - if (pud_none(*pud)) - pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); - - pmd = pmd_offset(pud, mpaddr); - if (pmd_none(*pmd)) - pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); -// pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); - - pte = pte_offset_map(pmd, mpaddr); - if (pte_none(*pte)) { -#ifdef CONFIG_DOMAIN0_CONTIGUOUS - if (d == dom0) p = map_new_domain0_page(mpaddr); - else -#endif - { - p = alloc_domheap_page(d); - // zero out pages for security reasons - memset(__va(page_to_phys(p)),0,PAGE_SIZE); - } - if (unlikely(!p)) { -printf("map_new_domain_page: Can't alloc!!!! Aaaargh!\n"); - return(p); - } -if (unlikely(page_to_phys(p) > vhpt_paddr && page_to_phys(p) < vhpt_pend)) { - printf("map_new_domain_page: reassigned vhpt page %p!!\n",page_to_phys(p)); -} - set_pte(pte, pfn_pte(page_to_phys(p) >> PAGE_SHIFT, - __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX))); - } - else printk("map_new_domain_page: mpaddr %lx already mapped!\n",mpaddr); - return p; -} - -/* map a physical address to the specified metaphysical addr */ -void map_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr) -{ - struct mm_struct *mm = d->arch.mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - if (!mm->pgd) { - printk("map_domain_page: domain pgd must exist!\n"); - return; - } - pgd = pgd_offset(mm,mpaddr); - if (pgd_none(*pgd)) - pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); - - pud = pud_offset(pgd, mpaddr); - if (pud_none(*pud)) - pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); - - pmd = pmd_offset(pud, mpaddr); - if (pmd_none(*pmd)) - pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); -// pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); - - pte = pte_offset_map(pmd, mpaddr); - if (pte_none(*pte)) { - set_pte(pte, pfn_pte(physaddr >> PAGE_SHIFT, - __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX))); - } - else printk("map_domain_page: mpaddr %lx already mapped!\n",mpaddr); -} - -void mpafoo(unsigned long mpaddr) -{ - extern unsigned long privop_trace; - if (mpaddr == 0x3800) - privop_trace = 1; -} - -unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr) -{ - struct mm_struct *mm = d->arch.mm; - pgd_t *pgd = pgd_offset(mm, mpaddr); - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - -#ifdef CONFIG_DOMAIN0_CONTIGUOUS - if (d == dom0) { - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - //printk("lookup_domain_mpa: bad dom0 mpaddr %p!\n",mpaddr); -//printk("lookup_domain_mpa: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size); - mpafoo(mpaddr); - } - pte_t pteval = pfn_pte(mpaddr >> PAGE_SHIFT, - __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)); - pte = &pteval; - return *(unsigned long *)pte; - } -#endif -tryagain: - if (pgd_present(*pgd)) { - pud = pud_offset(pgd,mpaddr); - if (pud_present(*pud)) { - pmd = pmd_offset(pud,mpaddr); - if (pmd_present(*pmd)) { - pte = pte_offset_map(pmd,mpaddr); - if (pte_present(*pte)) { -//printk("lookup_domain_page: found mapping for %lx, pte=%lx\n",mpaddr,pte_val(*pte)); - return *(unsigned long *)pte; - } - } - } - } - /* if lookup fails and mpaddr is "legal", "create" the page */ - if ((mpaddr >> PAGE_SHIFT) < d->max_pages) { - if (map_new_domain_page(d,mpaddr)) goto tryagain; - } - printk("lookup_domain_mpa: bad mpa %p (> %p\n", - mpaddr,d->max_pages<<PAGE_SHIFT); - mpafoo(mpaddr); - return 0; -} - -// FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE -#ifndef CONFIG_VTI -unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) -{ - unsigned long pte = lookup_domain_mpa(d,mpaddr); - unsigned long imva; - - pte &= _PAGE_PPN_MASK; - imva = __va(pte); - imva |= mpaddr & ~PAGE_MASK; - return(imva); -} -#else // CONFIG_VTI -unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) -{ - unsigned long imva = __gpa_to_mpa(d, mpaddr); - - return __va(imva); -} -#endif // CONFIG_VTI - -// remove following line if not privifying in memory -//#define HAVE_PRIVIFY_MEMORY -#ifndef HAVE_PRIVIFY_MEMORY -#define privify_memory(x,y) do {} while(0) -#endif - -// see arch/x86/xxx/domain_build.c -int elf_sanity_check(Elf_Ehdr *ehdr) -{ - return (IS_ELF(*ehdr)); -} - -static void copy_memory(void *dst, void *src, int size) -{ - int remain; - - if (IS_XEN_ADDRESS(dom0,src)) { - memcpy(dst,src,size); - } - else { - printf("About to call __copy_from_user(%p,%p,%d)\n", - dst,src,size); - while (remain = __copy_from_user(dst,src,size)) { - printf("incomplete user copy, %d remain of %d\n", - remain,size); - dst += size - remain; src += size - remain; - size -= remain; - } - } -} - -void loaddomainelfimage(struct domain *d, unsigned long image_start) -{ - char *elfbase = image_start; - //Elf_Ehdr *ehdr = (Elf_Ehdr *)image_start; - Elf_Ehdr ehdr; - Elf_Phdr phdr; - int h, filesz, memsz, paddr; - unsigned long elfaddr, dom_mpaddr, dom_imva; - struct page *p; - unsigned long pteval; - - copy_memory(&ehdr,image_start,sizeof(Elf_Ehdr)); - for ( h = 0; h < ehdr.e_phnum; h++ ) { - copy_memory(&phdr,elfbase + ehdr.e_phoff + (h*ehdr.e_phentsize), - sizeof(Elf_Phdr)); - //if ( !is_loadable_phdr(phdr) ) - if ((phdr.p_type != PT_LOAD)) { - continue; - } - filesz = phdr.p_filesz; memsz = phdr.p_memsz; - elfaddr = elfbase + phdr.p_offset; - dom_mpaddr = phdr.p_paddr; -//printf("p_offset: %x, size=%x\n",elfaddr,filesz); -#ifdef CONFIG_DOMAIN0_CONTIGUOUS - if (d == dom0) { - if (dom_mpaddr+memsz>dom0_size || dom_mpaddr+filesz>dom0_size) { - printf("Domain0 doesn't fit in allocated space!\n"); - while(1); - } - dom_imva = __va(dom_mpaddr + dom0_start); - copy_memory(dom_imva,elfaddr,filesz); - if (memsz > filesz) memset(dom_imva+filesz,0,memsz-filesz); -//FIXME: This test for code seems to find a lot more than objdump -x does - if (phdr.p_flags & PF_X) privify_memory(dom_imva,filesz); - } - else -#endif - while (memsz > 0) { -#ifdef DOMU_AUTO_RESTART - pteval = lookup_domain_mpa(d,dom_mpaddr); - if (pteval) dom_imva = __va(pteval & _PFN_MASK); - else { printf("loaddomainelfimage: BAD!\n"); while(1); } -#else - p = map_new_domain_page(d,dom_mpaddr); - if (unlikely(!p)) BUG(); - dom_imva = __va(page_to_phys(p)); -#endif - if (filesz > 0) { - if (filesz >= PAGE_SIZE) - copy_memory(dom_imva,elfaddr,PAGE_SIZE); - else { // copy partial page, zero the rest of page - copy_memory(dom_imva,elfaddr,filesz); - memset(dom_imva+filesz,0,PAGE_SIZE-filesz); - } -//FIXME: This test for code seems to find a lot more than objdump -x does - if (phdr.p_flags & PF_X) - privify_memory(dom_imva,PAGE_SIZE); - } - else if (memsz > 0) // always zero out entire page - memset(dom_imva,0,PAGE_SIZE); - memsz -= PAGE_SIZE; filesz -= PAGE_SIZE; - elfaddr += PAGE_SIZE; dom_mpaddr += PAGE_SIZE; - } - } -} - -int -parsedomainelfimage(char *elfbase, unsigned long elfsize, unsigned long *entry) -{ - Elf_Ehdr ehdr; - - copy_memory(&ehdr,elfbase,sizeof(Elf_Ehdr)); - - if ( !elf_sanity_check(&ehdr) ) { - printk("ELF sanity check failed.\n"); - return -EINVAL; - } - - if ( (ehdr.e_phoff + (ehdr.e_phnum * ehdr.e_phentsize)) > elfsize ) - { - printk("ELF program headers extend beyond end of image.\n"); - return -EINVAL; - } - - if ( (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) > elfsize ) - { - printk("ELF section headers extend beyond end of image.\n"); - return -EINVAL; - } - -#if 0 - /* Find the section-header strings table. */ - if ( ehdr.e_shstrndx == SHN_UNDEF ) - { - printk("ELF image has no section-header strings table (shstrtab).\n"); - return -EINVAL; - } -#endif - - *entry = ehdr.e_entry; -printf("parsedomainelfimage: entry point = %p\n",*entry); - - return 0; -} - - -void alloc_dom0(void) -{ -#ifdef CONFIG_DOMAIN0_CONTIGUOUS - if (platform_is_hp_ski()) { - dom0_size = 128*1024*1024; //FIXME: Should be configurable - } - printf("alloc_dom0: starting (initializing %d MB...)\n",dom0_size/(1024*1024)); - - /* FIXME: The first trunk (say 256M) should always be assigned to - * Dom0, since Dom0's physical == machine address for DMA purpose. - * Some old version linux, like 2.4, assumes physical memory existing - * in 2nd 64M space. - */ - dom0_start = alloc_boot_pages( - dom0_size >> PAGE_SHIFT, dom0_align >> PAGE_SHIFT); - dom0_start <<= PAGE_SHIFT; - if (!dom0_start) { - printf("construct_dom0: can't allocate contiguous memory size=%p\n", - dom0_size); - while(1); - } - printf("alloc_dom0: dom0_start=%p\n",dom0_start); -#else - dom0_start = 0; -#endif - -} - -#ifdef DOMU_BUILD_STAGING -void alloc_domU_staging(void) -{ - domU_staging_size = 32*1024*1024; //FIXME: Should be configurable - printf("alloc_domU_staging: starting (initializing %d MB...)\n",domU_staging_size/(1024*1024)); - domU_staging_start = alloc_boot_pages( - domU_staging_size >> PAGE_SHIFT, domU_staging_align >> PAGE_SHIFT); - domU_staging_start <<= PAGE_SHIFT; - if (!domU_staging_size) { - printf("alloc_domU_staging: can't allocate, spinning...\n"); - while(1); - } - else domU_staging_area = (unsigned long *)__va(domU_staging_start); - printf("alloc_domU_staging: domU_staging_area=%p\n",domU_staging_area); - -} - -unsigned long -domU_staging_read_8(unsigned long at) -{ - // no way to return errors so just do it - return domU_staging_area[at>>3]; - -} - -unsigned long -domU_staging_write_32(unsigned long at, unsigned long a, unsigned long b, - unsigned long c, unsigned long d) -{ - if (at + 32 > domU_staging_size) return -1; - if (at & 0x1f) return -1; - at >>= 3; - domU_staging_area[at++] = a; - domU_staging_area[at++] = b; - domU_staging_area[at++] = c; - domU_staging_area[at] = d; - return 0; - -} -#endif - -/* - * Domain 0 has direct access to all devices absolutely. However - * the major point of this stub here, is to allow alloc_dom_mem - * handled with order > 0 request. Dom0 requires that bit set to - * allocate memory for other domains. - */ -void physdev_init_dom0(struct domain *d) -{ - set_bit(_DOMF_physdev_access, &d->domain_flags); -} - -extern unsigned long running_on_sim; -unsigned int vmx_dom0 = 0; -int construct_dom0(struct domain *d, - unsigned long image_start, unsigned long image_len, - unsigned long initrd_start, unsigned long initrd_len, - char *cmdline) -{ - char *dst; - int i, rc; - unsigned long pfn, mfn; - unsigned long nr_pt_pages; - unsigned long count; - unsigned long alloc_start, alloc_end; - struct pfn_info *page = NULL; - start_info_t *si; - struct vcpu *v = d->vcpu[0]; - - struct domain_setup_info dsi; - unsigned long p_start; - unsigned long pkern_start; - unsigned long pkern_entry; - unsigned long pkern_end; - unsigned long ret, progress = 0; - -//printf("construct_dom0: starting\n"); - /* Sanity! */ -#ifndef CLONE_DOMAIN0 - if ( d != dom0 ) - BUG(); - if ( test_bit(_DOMF_constructed, &d->domain_flags) ) - BUG(); -#endif - - memset(&dsi, 0, sizeof(struct domain_setup_info)); - - printk("*** LOADING DOMAIN 0 ***\n"); - - alloc_start = dom0_start; - alloc_end = dom0_start + dom0_size; - d->tot_pages = d->max_pages = dom0_size/PAGE_SIZE; - image_start = __va(ia64_boot_param->initrd_start); - image_len = ia64_boot_param->initrd_size; -//printk("image_start=%lx, image_len=%lx\n",image_start,image_len); -//printk("First word of image: %lx\n",*(unsigned long *)image_start); - -//printf("construct_dom0: about to call parseelfimage\n"); - dsi.image_addr = (unsigned long)image_start; - dsi.image_len = image_len; - rc = parseelfimage(&dsi); - if ( rc != 0 ) - return rc; - -#ifdef CONFIG_VTI - /* Temp workaround */ - if (running_on_sim) - dsi.xen_section_string = (char *)1; - - /* Check whether dom0 is vti domain */ - if ((!vmx_enabled) && !dsi.xen_section_string) { - printk("Lack of hardware support for unmodified vmx dom0\n"); - panic(""); - } - - if (vmx_enabled && !dsi.xen_section_string) { - printk("Dom0 is vmx domain!\n"); - vmx_dom0 = 1; - } -#endif - - p_start = dsi.v_start; - pkern_start = dsi.v_kernstart; - pkern_end = dsi.v_kernend; - pkern_entry = dsi.v_kernentry; - -//printk("p_start=%lx, pkern_start=%lx, pkern_end=%lx, pkern_entry=%lx\n",p_start,pkern_start,pkern_end,pkern_entry); - - if ( (p_start & (PAGE_SIZE-1)) != 0 ) - { - printk("Initial guest OS must load to a page boundary.\n"); - return -EINVAL; - } - - printk("METAPHYSICAL MEMORY ARRANGEMENT:\n" - " Kernel image: %lx->%lx\n" - " Entry address: %lx\n" - " Init. ramdisk: (NOT IMPLEMENTED YET)\n", - pkern_start, pkern_end, pkern_entry); - - if ( (pkern_end - pkern_start) > (d->max_pages * PAGE_SIZE) ) - { - printk("Initial guest OS requires too much space\n" - "(%luMB is greater than %luMB limit)\n", - (pkern_end-pkern_start)>>20, (d->max_pages<<PAGE_SHIFT)>>20); - return -ENOMEM; - } - - // if high 3 bits of pkern start are non-zero, error - - // if pkern end is after end of metaphysical memory, error - // (we should be able to deal with this... later) - - - // - -#if 0 - strcpy(d->name,"Domain0"); -#endif - - /* Mask all upcalls... */ - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - -#ifdef CONFIG_VTI - /* Construct a frame-allocation list for the initial domain, since these - * pages are allocated by boot allocator and pfns are not set properly - */ - for ( mfn = (alloc_start>>PAGE_SHIFT); - mfn < (alloc_end>>PAGE_SHIFT); - mfn++ ) - { - page = &frame_table[mfn]; - page_set_owner(page, d); - page->u.inuse.type_info = 0; - page->count_info = PGC_allocated | 1; - list_add_tail(&page->list, &d->page_list); - - /* Construct 1:1 mapping */ - machine_to_phys_mapping[mfn] = mfn; - } - - /* Dom0's pfn is equal to mfn, so there's no need to allocate pmt - * for dom0 - */ - d->arch.pmt = NULL; -#endif - - /* Copy the OS image. */ - loaddomainelfimage(d,image_start); - - /* Copy the initial ramdisk. */ - //if ( initrd_len != 0 ) - // memcpy((void *)vinitrd_start, initrd_start, initrd_len); - - /* Sync d/i cache conservatively */ - ret = ia64_pal_cache_flush(4, 0, &progress, NULL); - if (ret != PAL_STATUS_SUCCESS) - panic("PAL CACHE FLUSH failed for dom0.\n"); - printk("Sync i/d cache for dom0 image SUCC\n"); - -#if 0 - /* Set up start info area. */ - //si = (start_info_t *)vstartinfo_start; - memset(si, 0, PAGE_SIZE); - si->nr_pages = d->tot_pages; - si->shared_info = virt_to_phys(d->shared_info); - si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN; - //si->pt_base = vpt_start; - //si->nr_pt_frames = nr_pt_pages; - //si->mfn_list = vphysmap_start; - - if ( initrd_len != 0 ) - { - //si->mod_start = vinitrd_start; - si->mod_len = initrd_len; - printk("Initrd len 0x%lx, start at 0x%08lx\n", - si->mod_len, si->mod_start); - } - - dst = si->cmd_line; - if ( cmdline != NULL ) - { - for ( i = 0; i < 255; i++ ) - { - if ( cmdline[i] == '\0' ) - break; - *dst++ = cmdline[i]; - } - } - *dst = '\0'; - - zap_low_mappings(); /* Do the same for the idle page tables. */ -#endif - - /* Give up the VGA console if DOM0 is configured to grab it. */ - if (cmdline != NULL) - console_endboot(strstr(cmdline, "tty0") != NULL); - - /* VMX specific construction for Dom0, if hardware supports VMX - * and Dom0 is unmodified image - */ - printk("Dom0: 0x%lx, domain: 0x%lx\n", (u64)dom0, (u64)d); - if (vmx_dom0) - vmx_final_setup_domain(dom0); - - set_bit(_DOMF_constructed, &d->domain_flags); - - new_thread(v, pkern_entry, 0, 0); - physdev_init_dom0(d); - - // FIXME: Hack for keyboard input -#ifdef CLONE_DOMAIN0 -if (d == dom0) -#endif - serial_input_init(); - if (d == dom0) { - VCPU(v, delivery_mask[0]) = -1L; - VCPU(v, delivery_mask[1]) = -1L; - VCPU(v, delivery_mask[2]) = -1L; - VCPU(v, delivery_mask[3]) = -1L; - } - else __set_bit(0x30, VCPU(v, delivery_mask)); - - return 0; -} - -// FIXME: When dom0 can construct domains, this goes away (or is rewritten) -int construct_domU(struct domain *d, - unsigned long image_start, unsigned long image_len, - unsigned long initrd_start, unsigned long initrd_len, - char *cmdline) -{ - int i, rc; - struct vcpu *v = d->vcpu[0]; - unsigned long pkern_entry; - -#ifndef DOMU_AUTO_RESTART - if ( test_bit(_DOMF_constructed, &d->domain_flags) ) BUG(); -#endif - - printk("*** LOADING DOMAIN %d ***\n",d->domain_id); - - d->max_pages = dom0_size/PAGE_SIZE; // FIXME: use dom0 size - // FIXME: use domain0 command line - rc = parsedomainelfimage(image_start, image_len, &pkern_entry); - printk("parsedomainelfimage returns %d\n",rc); - if ( rc != 0 ) return rc; - - /* Mask all upcalls... */ - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - - /* Copy the OS image. */ - printk("calling loaddomainelfimage(%p,%p)\n",d,image_start); - loaddomainelfimage(d,image_start); - printk("loaddomainelfimage returns\n"); - - set_bit(_DOMF_constructed, &d->domain_flags); - - printk("calling new_thread, entry=%p\n",pkern_entry); -#ifdef DOMU_AUTO_RESTART - v->domain->arch.image_start = image_start; - v->domain->arch.image_len = image_len; - v->domain->arch.entry = pkern_entry; -#endif - new_thread(v, pkern_entry, 0, 0); - printk("new_thread returns\n"); - __set_bit(0x30, VCPU(v, delivery_mask)); - - return 0; -} - -#ifdef DOMU_AUTO_RESTART -void reconstruct_domU(struct vcpu *v) -{ - /* re-copy the OS image to reset data values to original */ - printk("reconstruct_domU: restarting domain %d...\n", - v->domain->domain_id); - loaddomainelfimage(v->domain,v->domain->arch.image_start); - new_thread(v, v->domain->arch.entry, 0, 0); -} -#endif - -// FIXME: When dom0 can construct domains, this goes away (or is rewritten) -int launch_domainU(unsigned long size) -{ -#ifdef CLONE_DOMAIN0 - static int next = CLONE_DOMAIN0+1; -#else - static int next = 1; -#endif - - struct domain *d = do_createdomain(next,0); - if (!d) { - printf("launch_domainU: couldn't create\n"); - return 1; - } - else next++; - if (construct_domU(d, (unsigned long)domU_staging_area, size,0,0,0)) { - printf("launch_domainU: couldn't construct(id=%d,%lx,%lx)\n", - d->domain_id,domU_staging_area,size); - return 2; - } - domain_unpause_by_systemcontroller(d); -} - -void machine_restart(char * __unused) -{ - if (platform_is_hp_ski()) dummy(); - printf("machine_restart called: spinning....\n"); - while(1); -} - -void machine_halt(void) -{ - if (platform_is_hp_ski()) dummy(); - printf("machine_halt called: spinning....\n"); - while(1); -} - -void dummy_called(char *function) -{ - if (platform_is_hp_ski()) asm("break 0;;"); - printf("dummy called in %s: spinning....\n", function); - while(1); -} - - -#if 0 -void switch_to(struct vcpu *prev, struct vcpu *next) -{ - struct vcpu *last; - - __switch_to(prev,next,last); - //set_current(next); -} -#endif - -void domain_pend_keyboard_interrupt(int irq) -{ - vcpu_pend_interrupt(dom0->vcpu[0],irq); -} - -void vcpu_migrate_cpu(struct vcpu *v, int newcpu) -{ - if ( v->processor == newcpu ) - return; - - set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags); - v->processor = newcpu; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/grant_table.c --- a/xen/arch/ia64/grant_table.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1288 +0,0 @@ -#ifndef CONFIG_VTI -// temporarily in arch/ia64 until can merge into common/grant_table.c -/****************************************************************************** - * common/grant_table.c - * - * Mechanism for granting foreign access to page frames, and receiving - * page-ownership transfers. - * - * Copyright (c) 2005 Christopher Clark - * Copyright (c) 2004 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define GRANT_DEBUG 0 -#define GRANT_DEBUG_VERBOSE 0 - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/sched.h> -#include <xen/shadow.h> -#include <xen/mm.h> -#ifdef __ia64__ -#define __addr_ok(a) 1 // FIXME-ia64: a variant of access_ok?? -// FIXME-ia64: need to implement real cmpxchg_user on ia64 -//#define cmpxchg_user(_p,_o,_n) ((*_p == _o) ? ((*_p = _n), 0) : ((_o = *_p), 0)) -// FIXME-ia64: these belong in an asm/grant_table.h... PAGE_SIZE different -#undef ORDER_GRANT_FRAMES -//#undef NUM_GRANT_FRAMES -#define ORDER_GRANT_FRAMES 0 -//#define NUM_GRANT_FRAMES (1U << ORDER_GRANT_FRAMES) -#endif - -#define PIN_FAIL(_lbl, _rc, _f, _a...) \ - do { \ - DPRINTK( _f, ## _a ); \ - rc = (_rc); \ - goto _lbl; \ - } while ( 0 ) - -static inline int -get_maptrack_handle( - grant_table_t *t) -{ - unsigned int h; - if ( unlikely((h = t->maptrack_head) == t->maptrack_limit) ) - return -1; - t->maptrack_head = t->maptrack[h].ref_and_flags >> MAPTRACK_REF_SHIFT; - t->map_count++; - return h; -} - -static inline void -put_maptrack_handle( - grant_table_t *t, int handle) -{ - t->maptrack[handle].ref_and_flags = t->maptrack_head << MAPTRACK_REF_SHIFT; - t->maptrack_head = handle; - t->map_count--; -} - -static int -__gnttab_activate_grant_ref( - struct domain *mapping_d, /* IN */ - struct vcpu *mapping_ed, - struct domain *granting_d, - grant_ref_t ref, - u16 dev_hst_ro_flags, - unsigned long host_virt_addr, - unsigned long *pframe ) /* OUT */ -{ - domid_t sdom; - u16 sflags; - active_grant_entry_t *act; - grant_entry_t *sha; - s16 rc = 1; - unsigned long frame = 0; - int retries = 0; - - /* - * Objectives of this function: - * . Make the record ( granting_d, ref ) active, if not already. - * . Update shared grant entry of owner, indicating frame is mapped. - * . Increment the owner act->pin reference counts. - * . get_page on shared frame if new mapping. - * . get_page_type if this is first RW mapping of frame. - * . Add PTE to virtual address space of mapping_d, if necessary. - * Returns: - * . -ve: error - * . 1: ok - * . 0: ok and TLB invalidate of host_virt_addr needed. - * - * On success, *pframe contains mfn. - */ - - /* - * We bound the number of times we retry CMPXCHG on memory locations that - * we share with a guest OS. The reason is that the guest can modify that - * location at a higher rate than we can read-modify-CMPXCHG, so the guest - * could cause us to livelock. There are a few cases where it is valid for - * the guest to race our updates (e.g., to change the GTF_readonly flag), - * so we allow a few retries before failing. - */ - - act = &granting_d->grant_table->active[ref]; - sha = &granting_d->grant_table->shared[ref]; - - spin_lock(&granting_d->grant_table->lock); - - if ( act->pin == 0 ) - { - /* CASE 1: Activating a previously inactive entry. */ - - sflags = sha->flags; - sdom = sha->domid; - - for ( ; ; ) - { - u32 scombo, prev_scombo, new_scombo; - - if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) || - unlikely(sdom != mapping_d->domain_id) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", - sflags, sdom, mapping_d->domain_id); - - /* Merge two 16-bit values into a 32-bit combined update. */ - /* NB. Endianness! */ - prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; - - new_scombo = scombo | GTF_reading; - if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) - { - new_scombo |= GTF_writing; - if ( unlikely(sflags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - } - - /* NB. prev_scombo is updated in place to seen value. */ - if ( unlikely(cmpxchg_user((u32 *)&sha->flags, - prev_scombo, - new_scombo)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Fault while modifying shared flags and domid.\n"); - - /* Did the combined update work (did we see what we expected?). */ - if ( likely(prev_scombo == scombo) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - /* Didn't see what we expected. Split out the seen flags & dom. */ - /* NB. Endianness! */ - sflags = (u16)prev_scombo; - sdom = (u16)(prev_scombo >> 16); - } - - /* rmb(); */ /* not on x86 */ - - frame = __gpfn_to_mfn_foreign(granting_d, sha->frame); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( unlikely(!pfn_valid(frame)) || - unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ? - get_page(&frame_table[frame], granting_d) : - get_page_and_type(&frame_table[frame], granting_d, - PGT_writable_page))) ) - { - clear_bit(_GTF_writing, &sha->flags); - clear_bit(_GTF_reading, &sha->flags); - PIN_FAIL(unlock_out, GNTST_general_error, - "Could not pin the granted frame (%lx)!\n", frame); - } -#endif - - if ( dev_hst_ro_flags & GNTMAP_device_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_devr_inc : GNTPIN_devw_inc; - if ( dev_hst_ro_flags & GNTMAP_host_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_hstr_inc : GNTPIN_hstw_inc; - act->domid = sdom; - act->frame = frame; - } - else - { - /* CASE 2: Active modications to an already active entry. */ - - /* - * A cheesy check for possible pin-count overflow. - * A more accurate check cannot be done with a single comparison. - */ - if ( (act->pin & 0x80808080U) != 0 ) - PIN_FAIL(unlock_out, ENOSPC, - "Risk of counter overflow %08x\n", act->pin); - - frame = act->frame; - - if ( !(dev_hst_ro_flags & GNTMAP_readonly) && - !((sflags = sha->flags) & GTF_writing) ) - { - for ( ; ; ) - { - u16 prev_sflags; - - if ( unlikely(sflags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - - prev_sflags = sflags; - - /* NB. prev_sflags is updated in place to seen value. */ - if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags, - prev_sflags | GTF_writing)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Fault while modifying shared flags.\n"); - - if ( likely(prev_sflags == sflags) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - sflags = prev_sflags; - } - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( unlikely(!get_page_type(&frame_table[frame], - PGT_writable_page)) ) - { - clear_bit(_GTF_writing, &sha->flags); - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a unwritable page.\n"); - } -#endif - } - - if ( dev_hst_ro_flags & GNTMAP_device_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_devr_inc : GNTPIN_devw_inc; - - if ( dev_hst_ro_flags & GNTMAP_host_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_hstr_inc : GNTPIN_hstw_inc; - } - - /* - * At this point: - * act->pin updated to reflect mapping. - * sha->flags updated to indicate to granting domain mapping done. - * frame contains the mfn. - */ - - spin_unlock(&granting_d->grant_table->lock); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( (host_virt_addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) ) - { - /* Write update into the pagetable. */ - l1_pgentry_t pte; - pte = l1e_from_pfn(frame, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); - if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) - l1e_add_flags(pte,_PAGE_RW); - rc = update_grant_va_mapping( host_virt_addr, pte, - mapping_d, mapping_ed ); - - /* - * IMPORTANT: (rc == 0) => must flush / invalidate entry in TLB. - * This is done in the outer gnttab_map_grant_ref. - */ - - if ( rc < 0 ) - { - /* Failure: undo and abort. */ - - spin_lock(&granting_d->grant_table->lock); - - if ( dev_hst_ro_flags & GNTMAP_readonly ) - { - act->pin -= GNTPIN_hstr_inc; - } - else - { - act->pin -= GNTPIN_hstw_inc; - if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - } - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); - } - - spin_unlock(&granting_d->grant_table->lock); - } - - } -#endif - - *pframe = frame; - return rc; - - unlock_out: - spin_unlock(&granting_d->grant_table->lock); - return rc; -} - -/* - * Returns 0 if TLB flush / invalidate required by caller. - * va will indicate the address to be invalidated. - */ -static int -__gnttab_map_grant_ref( - gnttab_map_grant_ref_t *uop, - unsigned long *va) -{ - domid_t dom; - grant_ref_t ref; - struct domain *ld, *rd; - struct vcpu *led; - u16 dev_hst_ro_flags; - int handle; - unsigned long frame = 0, host_virt_addr; - int rc; - - led = current; - ld = led->domain; - - /* Bitwise-OR avoids short-circuiting which screws control flow. */ - if ( unlikely(__get_user(dom, &uop->dom) | - __get_user(ref, &uop->ref) | - __get_user(host_virt_addr, &uop->host_addr) | - __get_user(dev_hst_ro_flags, &uop->flags)) ) - { - DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n"); - return -EFAULT; /* don't set status */ - } - - - if ( ((host_virt_addr != 0) || (dev_hst_ro_flags & GNTMAP_host_map)) && - unlikely(!__addr_ok(host_virt_addr))) - { - DPRINTK("Bad virtual address (%lx) or flags (%x).\n", - host_virt_addr, dev_hst_ro_flags); - (void)__put_user(GNTST_bad_virt_addr, &uop->handle); - return GNTST_bad_gntref; - } - - if ( unlikely(ref >= NR_GRANT_ENTRIES) || - unlikely((dev_hst_ro_flags & - (GNTMAP_device_map|GNTMAP_host_map)) == 0) ) - { - DPRINTK("Bad ref (%d) or flags (%x).\n", ref, dev_hst_ro_flags); - (void)__put_user(GNTST_bad_gntref, &uop->handle); - return GNTST_bad_gntref; - } - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - DPRINTK("Could not find domain %d\n", dom); - (void)__put_user(GNTST_bad_domain, &uop->handle); - return GNTST_bad_domain; - } - - /* Get a maptrack handle. */ - if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) ) - { - int i; - grant_mapping_t *new_mt; - grant_table_t *lgt = ld->grant_table; - - /* Grow the maptrack table. */ - new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1); - if ( new_mt == NULL ) - { - put_domain(rd); - DPRINTK("No more map handles available\n"); - (void)__put_user(GNTST_no_device_space, &uop->handle); - return GNTST_no_device_space; - } - - memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order); - for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ ) - new_mt[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; - - free_xenheap_pages(lgt->maptrack, lgt->maptrack_order); - lgt->maptrack = new_mt; - lgt->maptrack_order += 1; - lgt->maptrack_limit <<= 1; - - printk("Doubled maptrack size\n"); - handle = get_maptrack_handle(ld->grant_table); - } - -#if GRANT_DEBUG_VERBOSE - DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n", - ref, dom, dev_hst_ro_flags); -#endif - - if ( 0 <= ( rc = __gnttab_activate_grant_ref( ld, led, rd, ref, - dev_hst_ro_flags, - host_virt_addr, &frame))) - { - /* - * Only make the maptrack live _after_ writing the pte, in case we - * overwrite the same frame number, causing a maptrack walk to find it - */ - ld->grant_table->maptrack[handle].domid = dom; - - ld->grant_table->maptrack[handle].ref_and_flags - = (ref << MAPTRACK_REF_SHIFT) | - (dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK); - - (void)__put_user(frame, &uop->dev_bus_addr); - - if ( dev_hst_ro_flags & GNTMAP_host_map ) - *va = host_virt_addr; - - (void)__put_user(handle, &uop->handle); - } - else - { - (void)__put_user(rc, &uop->handle); - put_maptrack_handle(ld->grant_table, handle); - } - - put_domain(rd); - return rc; -} - -static long -gnttab_map_grant_ref( - gnttab_map_grant_ref_t *uop, unsigned int count) -{ - int i, flush = 0; - unsigned long va = 0; - - for ( i = 0; i < count; i++ ) - if ( __gnttab_map_grant_ref(&uop[i], &va) == 0 ) - flush++; - -#ifdef __ia64__ -// FIXME-ia64: probably need to do something here to avoid stale mappings? -#else - if ( flush == 1 ) - flush_tlb_one_mask(current->domain->cpumask, va); - else if ( flush != 0 ) - flush_tlb_mask(current->domain->cpumask); -#endif - - return 0; -} - -static int -__gnttab_unmap_grant_ref( - gnttab_unmap_grant_ref_t *uop, - unsigned long *va) -{ - domid_t dom; - grant_ref_t ref; - u16 handle; - struct domain *ld, *rd; - - active_grant_entry_t *act; - grant_entry_t *sha; - grant_mapping_t *map; - u16 flags; - s16 rc = 1; - unsigned long frame, virt; - - ld = current->domain; - - /* Bitwise-OR avoids short-circuiting which screws control flow. */ - if ( unlikely(__get_user(virt, &uop->host_addr) | - __get_user(frame, &uop->dev_bus_addr) | - __get_user(handle, &uop->handle)) ) - { - DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n"); - return -EFAULT; /* don't set status */ - } - - map = &ld->grant_table->maptrack[handle]; - - if ( unlikely(handle >= ld->grant_table->maptrack_limit) || - unlikely(!(map->ref_and_flags & MAPTRACK_GNTMAP_MASK)) ) - { - DPRINTK("Bad handle (%d).\n", handle); - (void)__put_user(GNTST_bad_handle, &uop->status); - return GNTST_bad_handle; - } - - dom = map->domid; - ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; - flags = map->ref_and_flags & MAPTRACK_GNTMAP_MASK; - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - DPRINTK("Could not find domain %d\n", dom); - (void)__put_user(GNTST_bad_domain, &uop->status); - return GNTST_bad_domain; - } - -#if GRANT_DEBUG_VERBOSE - DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n", - ref, dom, handle); -#endif - - act = &rd->grant_table->active[ref]; - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - - if ( frame == 0 ) - { - frame = act->frame; - } - else - { - if ( unlikely(frame != act->frame) ) - PIN_FAIL(unmap_out, GNTST_general_error, - "Bad frame number doesn't match gntref.\n"); - if ( flags & GNTMAP_device_map ) - act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc - : GNTPIN_devw_inc; - - map->ref_and_flags &= ~GNTMAP_device_map; - (void)__put_user(0, &uop->dev_bus_addr); - - /* Frame is now unmapped for device access. */ - } - - if ( (virt != 0) && - (flags & GNTMAP_host_map) && - ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0)) - { -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - l1_pgentry_t *pl1e; - unsigned long _ol1e; - - pl1e = &linear_pg_table[l1_linear_offset(virt)]; - - if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) ) - { - DPRINTK("Could not find PTE entry for address %lx\n", virt); - rc = -EINVAL; - goto unmap_out; - } - - /* - * Check that the virtual address supplied is actually mapped to - * act->frame. - */ - if ( unlikely((_ol1e >> PAGE_SHIFT) != frame )) - { - DPRINTK("PTE entry %lx for address %lx doesn't match frame %lx\n", - _ol1e, virt, frame); - rc = -EINVAL; - goto unmap_out; - } - - /* Delete pagetable entry. */ - if ( unlikely(__put_user(0, (unsigned long *)pl1e))) - { - DPRINTK("Cannot delete PTE entry at %p for virtual address %lx\n", - pl1e, virt); - rc = -EINVAL; - goto unmap_out; - } -#endif - - map->ref_and_flags &= ~GNTMAP_host_map; - - act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc - : GNTPIN_hstw_inc; - - rc = 0; - *va = virt; - } - - if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) - { - map->ref_and_flags = 0; - put_maptrack_handle(ld->grant_table, handle); - } - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? I think not and then -// this can probably be macro-ized into nothingness -#else - /* If just unmapped a writable mapping, mark as dirtied */ - if ( unlikely(shadow_mode_log_dirty(rd)) && - !( flags & GNTMAP_readonly ) ) - mark_dirty(rd, frame); -#endif - - /* If the last writable mapping has been removed, put_page_type */ - if ( ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask) ) == 0) && - ( !( flags & GNTMAP_readonly ) ) ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); - } - - unmap_out: - (void)__put_user(rc, &uop->status); - spin_unlock(&rd->grant_table->lock); - put_domain(rd); - return rc; -} - -static long -gnttab_unmap_grant_ref( - gnttab_unmap_grant_ref_t *uop, unsigned int count) -{ - int i, flush = 0; - unsigned long va = 0; - - for ( i = 0; i < count; i++ ) - if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 ) - flush++; - -#ifdef __ia64__ -// FIXME-ia64: probably need to do something here to avoid stale mappings? -#else - if ( flush == 1 ) - flush_tlb_one_mask(current->domain->cpumask, va); - else if ( flush != 0 ) - flush_tlb_mask(current->domain->cpumask); -#endif - - return 0; -} - -static long -gnttab_setup_table( - gnttab_setup_table_t *uop, unsigned int count) -{ - gnttab_setup_table_t op; - struct domain *d; - int i; - unsigned long addr; - - if ( count != 1 ) - return -EINVAL; - - if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) - { - DPRINTK("Fault while reading gnttab_setup_table_t.\n"); - return -EFAULT; - } - - if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) ) - { - DPRINTK("Xen only supports up to %d grant-table frames per domain.\n", - NR_GRANT_FRAMES); - (void)put_user(GNTST_general_error, &uop->status); - return 0; - } - - if ( op.dom == DOMID_SELF ) - { - op.dom = current->domain->domain_id; - } - else if ( unlikely(!IS_PRIV(current->domain)) ) - { - (void)put_user(GNTST_permission_denied, &uop->status); - return 0; - } - - if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) - { - DPRINTK("Bad domid %d.\n", op.dom); - (void)put_user(GNTST_bad_domain, &uop->status); - return 0; - } - - if ( op.nr_frames <= NR_GRANT_FRAMES ) - { - ASSERT(d->grant_table != NULL); - (void)put_user(GNTST_okay, &uop->status); -#ifdef __ia64__ - if (d == dom0) { - for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user( - (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, - &uop->frame_list[i]); - } else { - /* IA64 hack - need to map it somewhere */ - addr = (1UL << 40); - map_domain_page(d, addr, virt_to_phys(d->grant_table->shared)); - (void)put_user(addr >> PAGE_SHIFT, &uop->frame_list[0]); - } -#else - for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user( - (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, - &uop->frame_list[i]); -#endif - } - - put_domain(d); - return 0; -} - -#if GRANT_DEBUG -static int -gnttab_dump_table(gnttab_dump_table_t *uop) -{ - grant_table_t *gt; - gnttab_dump_table_t op; - struct domain *d; - u32 shared_mfn; - active_grant_entry_t *act; - grant_entry_t sha_copy; - grant_mapping_t *maptrack; - int i; - - - if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) - { - DPRINTK("Fault while reading gnttab_dump_table_t.\n"); - return -EFAULT; - } - - if ( op.dom == DOMID_SELF ) - { - op.dom = current->domain->domain_id; - } - - if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) - { - DPRINTK("Bad domid %d.\n", op.dom); - (void)put_user(GNTST_bad_domain, &uop->status); - return 0; - } - - ASSERT(d->grant_table != NULL); - gt = d->grant_table; - (void)put_user(GNTST_okay, &uop->status); - - shared_mfn = virt_to_phys(d->grant_table->shared); - - DPRINTK("Grant table for dom (%hu) MFN (%x)\n", - op.dom, shared_mfn); - - ASSERT(d->grant_table->active != NULL); - ASSERT(d->grant_table->shared != NULL); - ASSERT(d->grant_table->maptrack != NULL); - - for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) - { - sha_copy = gt->shared[i]; - - if ( sha_copy.flags ) - { - DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) " - "dom:(%hu) frame:(%lx)\n", - op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame); - } - } - - spin_lock(>->lock); - - for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) - { - act = >->active[i]; - - if ( act->pin ) - { - DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) " - "dom:(%hu) frame:(%lx)\n", - op.dom, i, act->pin, act->domid, act->frame); - } - } - - for ( i = 0; i < gt->maptrack_limit; i++ ) - { - maptrack = >->maptrack[i]; - - if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK ) - { - DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) " - "dom:(%hu)\n", - op.dom, i, - maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT, - maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK, - maptrack->domid); - } - } - - spin_unlock(>->lock); - - put_domain(d); - return 0; -} -#endif - -long -do_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) -{ - long rc; - - if ( count > 512 ) - return -EINVAL; - - LOCK_BIGLOCK(current->domain); - - rc = -EFAULT; - switch ( cmd ) - { - case GNTTABOP_map_grant_ref: - if ( unlikely(!array_access_ok( - uop, count, sizeof(gnttab_map_grant_ref_t))) ) - goto out; - rc = gnttab_map_grant_ref((gnttab_map_grant_ref_t *)uop, count); - break; - case GNTTABOP_unmap_grant_ref: - if ( unlikely(!array_access_ok( - uop, count, sizeof(gnttab_unmap_grant_ref_t))) ) - goto out; - rc = gnttab_unmap_grant_ref((gnttab_unmap_grant_ref_t *)uop, count); - break; - case GNTTABOP_setup_table: - rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count); - break; -#if GRANT_DEBUG - case GNTTABOP_dump_table: - rc = gnttab_dump_table((gnttab_dump_table_t *)uop); - break; -#endif - default: - rc = -ENOSYS; - break; - } - -out: - UNLOCK_BIGLOCK(current->domain); - - return rc; -} - -int -gnttab_check_unmap( - struct domain *rd, struct domain *ld, unsigned long frame, int readonly) -{ - /* Called when put_page is invoked on a page belonging to a foreign domain. - * Instead of decrementing the frame table ref count, locate the grant - * table entry, if any, and if found, decrement that count. - * Called a _lot_ at domain creation because pages mapped by priv domains - * also traverse this. - */ - - /* Note: If the same frame is mapped multiple times, and then one of - * the ptes is overwritten, which maptrack handle gets invalidated? - * Advice: Don't do it. Explicitly unmap. - */ - - unsigned int handle, ref, refcount; - grant_table_t *lgt, *rgt; - active_grant_entry_t *act; - grant_mapping_t *map; - int found = 0; - - lgt = ld->grant_table; - -#if GRANT_DEBUG_VERBOSE - if ( ld->domain_id != 0 ) - { - DPRINTK("Foreign unref rd(%d) ld(%d) frm(%x) flgs(%x).\n", - rd->domain_id, ld->domain_id, frame, readonly); - } -#endif - - /* Fast exit if we're not mapping anything using grant tables */ - if ( lgt->map_count == 0 ) - return 0; - - if ( get_domain(rd) == 0 ) - { - DPRINTK("gnttab_check_unmap: couldn't get_domain rd(%d)\n", - rd->domain_id); - return 0; - } - - rgt = rd->grant_table; - - for ( handle = 0; handle < lgt->maptrack_limit; handle++ ) - { - map = &lgt->maptrack[handle]; - - if ( ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK ) && - ( readonly ? 1 : (!(map->ref_and_flags & GNTMAP_readonly)))) - { - ref = (map->ref_and_flags >> MAPTRACK_REF_SHIFT); - act = &rgt->active[ref]; - - spin_lock(&rgt->lock); - - if ( act->frame != frame ) - { - spin_unlock(&rgt->lock); - continue; - } - - refcount = act->pin & ( readonly ? GNTPIN_hstr_mask - : GNTPIN_hstw_mask ); - if ( refcount == 0 ) - { - spin_unlock(&rgt->lock); - continue; - } - - /* gotcha */ - DPRINTK("Grant unref rd(%d) ld(%d) frm(%lx) flgs(%x).\n", - rd->domain_id, ld->domain_id, frame, readonly); - - if ( readonly ) - act->pin -= GNTPIN_hstr_inc; - else - { - act->pin -= GNTPIN_hstw_inc; - - /* any more granted writable mappings? */ - if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) - { - clear_bit(_GTF_writing, &rgt->shared[ref].flags); - put_page_type(&frame_table[frame]); - } - } - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &rgt->shared[ref].flags); - put_page(&frame_table[frame]); - } - spin_unlock(&rgt->lock); - - clear_bit(GNTMAP_host_map, &map->ref_and_flags); - - if ( !(map->ref_and_flags & GNTMAP_device_map) ) - put_maptrack_handle(lgt, handle); - - found = 1; - break; - } - } - put_domain(rd); - - return found; -} - -int -gnttab_prepare_for_transfer( - struct domain *rd, struct domain *ld, grant_ref_t ref) -{ - grant_table_t *rgt; - grant_entry_t *sha; - domid_t sdom; - u16 sflags; - u32 scombo, prev_scombo; - int retries = 0; - unsigned long target_pfn; - - DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n", - rd->domain_id, ld->domain_id, ref); - - if ( unlikely((rgt = rd->grant_table) == NULL) || - unlikely(ref >= NR_GRANT_ENTRIES) ) - { - DPRINTK("Dom %d has no g.t., or ref is bad (%d).\n", - rd->domain_id, ref); - return 0; - } - - spin_lock(&rgt->lock); - - sha = &rgt->shared[ref]; - - sflags = sha->flags; - sdom = sha->domid; - - for ( ; ; ) - { - target_pfn = sha->frame; - - if ( unlikely(target_pfn >= max_page ) ) - { - DPRINTK("Bad pfn (%lx)\n", target_pfn); - goto fail; - } - - if ( unlikely(sflags != GTF_accept_transfer) || - unlikely(sdom != ld->domain_id) ) - { - DPRINTK("Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", - sflags, sdom, ld->domain_id); - goto fail; - } - - /* Merge two 16-bit values into a 32-bit combined update. */ - /* NB. Endianness! */ - prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; - - /* NB. prev_scombo is updated in place to seen value. */ - if ( unlikely(cmpxchg_user((u32 *)&sha->flags, prev_scombo, - prev_scombo | GTF_transfer_committed)) ) - { - DPRINTK("Fault while modifying shared flags and domid.\n"); - goto fail; - } - - /* Did the combined update work (did we see what we expected?). */ - if ( likely(prev_scombo == scombo) ) - break; - - if ( retries++ == 4 ) - { - DPRINTK("Shared grant entry is unstable.\n"); - goto fail; - } - - /* Didn't see what we expected. Split out the seen flags & dom. */ - /* NB. Endianness! */ - sflags = (u16)prev_scombo; - sdom = (u16)(prev_scombo >> 16); - } - - spin_unlock(&rgt->lock); - return 1; - - fail: - spin_unlock(&rgt->lock); - return 0; -} - -void -gnttab_notify_transfer( - struct domain *rd, struct domain *ld, grant_ref_t ref, unsigned long frame) -{ - grant_entry_t *sha; - unsigned long pfn; - - DPRINTK("gnttab_notify_transfer rd(%hu) ld(%hu) ref(%hu).\n", - rd->domain_id, ld->domain_id, ref); - - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - pfn = sha->frame; - - if ( unlikely(pfn >= max_page ) ) - DPRINTK("Bad pfn (%lx)\n", pfn); - else - { - machine_to_phys_mapping[frame] = pfn; - - if ( unlikely(shadow_mode_log_dirty(ld))) - mark_dirty(ld, frame); - - if (shadow_mode_translate(ld)) - __phys_to_machine_mapping[pfn] = frame; - } -#endif - sha->frame = __mfn_to_gpfn(rd, frame); - sha->domid = rd->domain_id; - wmb(); - sha->flags = ( GTF_accept_transfer | GTF_transfer_completed ); - - spin_unlock(&rd->grant_table->lock); - - return; -} - -int -grant_table_create( - struct domain *d) -{ - grant_table_t *t; - int i; - - if ( (t = xmalloc(grant_table_t)) == NULL ) - goto no_mem; - - /* Simple stuff. */ - memset(t, 0, sizeof(*t)); - spin_lock_init(&t->lock); - - /* Active grant table. */ - if ( (t->active = xmalloc_array(active_grant_entry_t, NR_GRANT_ENTRIES)) - == NULL ) - goto no_mem; - memset(t->active, 0, sizeof(active_grant_entry_t) * NR_GRANT_ENTRIES); - - /* Tracking of mapped foreign frames table */ - if ( (t->maptrack = alloc_xenheap_page()) == NULL ) - goto no_mem; - t->maptrack_order = 0; - t->maptrack_limit = PAGE_SIZE / sizeof(grant_mapping_t); - memset(t->maptrack, 0, PAGE_SIZE); - for ( i = 0; i < t->maptrack_limit; i++ ) - t->maptrack[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; - - /* Shared grant table. */ - t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES); - if ( t->shared == NULL ) - goto no_mem; - memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE); - -#ifdef __ia64__ -// I don't think there's anything to do here on ia64?... -#else - for ( i = 0; i < NR_GRANT_FRAMES; i++ ) - { - SHARE_PFN_WITH_DOMAIN( - virt_to_page((char *)(t->shared)+(i*PAGE_SIZE)), d); - machine_to_phys_mapping[(virt_to_phys(t->shared) >> PAGE_SHIFT) + i] = - INVALID_M2P_ENTRY; - } -#endif - - /* Okay, install the structure. */ - wmb(); /* avoid races with lock-free access to d->grant_table */ - d->grant_table = t; - return 0; - - no_mem: - if ( t != NULL ) - { - xfree(t->active); - if ( t->maptrack != NULL ) - free_xenheap_page(t->maptrack); - xfree(t); - } - return -ENOMEM; -} - -void -gnttab_release_dev_mappings(grant_table_t *gt) -{ - grant_mapping_t *map; - domid_t dom; - grant_ref_t ref; - u16 handle; - struct domain *ld, *rd; - unsigned long frame; - active_grant_entry_t *act; - grant_entry_t *sha; - - ld = current->domain; - - for ( handle = 0; handle < gt->maptrack_limit; handle++ ) - { - map = >->maptrack[handle]; - - if ( map->ref_and_flags & GNTMAP_device_map ) - { - dom = map->domid; - ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; - - DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n", - handle, ref, - map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom); - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - - printk(KERN_WARNING "Grant release: No dom%d\n", dom); - continue; - } - - act = &rd->grant_table->active[ref]; - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - - if ( act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask) ) - { - frame = act->frame; - - if ( ( (act->pin & GNTPIN_hstw_mask) == 0 ) && - ( (act->pin & GNTPIN_devw_mask) > 0 ) ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - - act->pin &= ~(GNTPIN_devw_mask | GNTPIN_devr_mask); - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &sha->flags); - map->ref_and_flags = 0; - put_page(&frame_table[frame]); - } - else - map->ref_and_flags &= ~GNTMAP_device_map; - } - - spin_unlock(&rd->grant_table->lock); - - put_domain(rd); - } - } -} - - -void -grant_table_destroy( - struct domain *d) -{ - grant_table_t *t; - - if ( (t = d->grant_table) != NULL ) - { - /* Free memory relating to this grant table. */ - d->grant_table = NULL; - free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES); - free_xenheap_page(t->maptrack); - xfree(t->active); - xfree(t); - } -} - -void -grant_table_init( - void) -{ - /* Nothing. */ -} -#endif - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/hpsimserial.c --- a/xen/arch/ia64/hpsimserial.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,23 +0,0 @@ -/* - * HP Ski simulator serial I/O - * - * Copyright (C) 2004 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ - -#include <linux/config.h> -#include <xen/sched.h> -#include <xen/serial.h> -#include "hpsim_ssc.h" - -static void hp_ski_putc(struct serial_port *port, char c) -{ - ia64_ssc(c,0,0,0,SSC_PUTCHAR); -} - -static struct uart_driver hp_ski = { .putc = hp_ski_putc }; - -void hpsim_serial_init(void) -{ - serial_register_uart(0, &hp_ski, 0); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/hypercall.c --- a/xen/arch/ia64/hypercall.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,182 +0,0 @@ -/* - * Hypercall implementations - * - * Copyright (C) 2005 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <xen/config.h> -#include <xen/sched.h> - -#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ -#include <asm/sal.h> /* FOR struct ia64_sal_retval */ - -#include <asm/vcpu.h> -#include <asm/dom_fw.h> - -extern unsigned long translate_domain_mpaddr(unsigned long); -extern struct ia64_pal_retval xen_pal_emulator(UINT64,UINT64,UINT64,UINT64); -extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); - -unsigned long idle_when_pending = 0; -unsigned long pal_halt_light_count = 0; - -int -ia64_hypercall (struct pt_regs *regs) -{ - struct vcpu *v = (struct domain *) current; - struct ia64_sal_retval x; - struct ia64_pal_retval y; - unsigned long *tv, *tc; - int pi; - - switch (regs->r2) { - case FW_HYPERCALL_PAL_CALL: - //printf("*** PAL hypercall: index=%d\n",regs->r28); - //FIXME: This should call a C routine -#if 0 - // This is very conservative, but avoids a possible - // (and deadly) freeze in paravirtualized domains due - // to a yet-to-be-found bug where pending_interruption - // is zero when it shouldn't be. Since PAL is called - // in the idle loop, this should resolve it - VCPU(v,pending_interruption) = 1; -#endif - if (regs->r28 == PAL_HALT_LIGHT) { -#define SPURIOUS_VECTOR 15 - pi = vcpu_check_pending_interrupts(v); - if (pi != SPURIOUS_VECTOR) { - if (!VCPU(v,pending_interruption)) - idle_when_pending++; - vcpu_pend_unspecified_interrupt(v); -//printf("idle w/int#%d pending!\n",pi); -//this shouldn't happen, but it apparently does quite a bit! so don't -//allow it to happen... i.e. if a domain has an interrupt pending and -//it tries to halt itself because it thinks it is idle, just return here -//as deliver_pending_interrupt is called on the way out and will deliver it - } - else { - pal_halt_light_count++; - do_sched_op(SCHEDOP_yield); - } - //break; - } - else if (regs->r28 >= PAL_COPY_PAL) { /* FIXME */ - printf("stacked PAL hypercalls not supported\n"); - regs->r8 = -1; - break; - } - else y = xen_pal_emulator(regs->r28,regs->r29, - regs->r30,regs->r31); - regs->r8 = y.status; regs->r9 = y.v0; - regs->r10 = y.v1; regs->r11 = y.v2; - break; - 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), - vcpu_get_gr(v,38),vcpu_get_gr(v,39)); - regs->r8 = x.status; regs->r9 = x.v0; - regs->r10 = x.v1; regs->r11 = x.v2; - break; - case FW_HYPERCALL_EFI_RESET_SYSTEM: - printf("efi.reset_system called "); - if (current->domain == dom0) { - printf("(by dom0)\n "); - (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL); - } -#ifdef DOMU_AUTO_RESTART - else { - reconstruct_domU(current); - return 0; // don't increment ip! - } -#else - printf("(not supported for non-0 domain)\n"); - regs->r8 = EFI_UNSUPPORTED; -#endif - break; - case FW_HYPERCALL_EFI_GET_TIME: - tv = vcpu_get_gr(v,32); - tc = vcpu_get_gr(v,33); - //printf("efi_get_time(%p,%p) called...",tv,tc); - tv = __va(translate_domain_mpaddr(tv)); - if (tc) tc = __va(translate_domain_mpaddr(tc)); - regs->r8 = (*efi.get_time)(tv,tc); - //printf("and returns %lx\n",regs->r8); - break; - case FW_HYPERCALL_EFI_SET_TIME: - case FW_HYPERCALL_EFI_GET_WAKEUP_TIME: - case FW_HYPERCALL_EFI_SET_WAKEUP_TIME: - // FIXME: need fixes in efi.h from 2.6.9 - case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP: - // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED - // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS - // POINTER ARGUMENTS WILL BE VIRTUAL!! - case FW_HYPERCALL_EFI_GET_VARIABLE: - // FIXME: need fixes in efi.h from 2.6.9 - case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE: - case FW_HYPERCALL_EFI_SET_VARIABLE: - case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT: - // FIXME: need fixes in efi.h from 2.6.9 - regs->r8 = EFI_UNSUPPORTED; - break; - case 0xffff: // test dummy hypercall - regs->r8 = dump_privop_counts_to_user( - vcpu_get_gr(v,32), - vcpu_get_gr(v,33)); - break; - case 0xfffe: // test dummy hypercall - regs->r8 = zero_privop_counts_to_user( - vcpu_get_gr(v,32), - vcpu_get_gr(v,33)); - break; - case 0xfffd: // test dummy hypercall - regs->r8 = launch_domainU( - vcpu_get_gr(v,32)); - break; - case 0xfffc: // test dummy hypercall - regs->r8 = domU_staging_write_32( - 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)); - break; - case 0xfffb: // test dummy hypercall - regs->r8 = domU_staging_read_8(vcpu_get_gr(v,32)); - break; - - case __HYPERVISOR_dom0_op: - regs->r8 = do_dom0_op(regs->r14); - break; - - case __HYPERVISOR_dom_mem_op: -#ifdef CONFIG_VTI - regs->r8 = do_dom_mem_op(regs->r14, regs->r15, regs->r16, regs->r17, regs->r18); -#else - /* we don't handle reservations; just return success */ - regs->r8 = regs->r16; -#endif - break; - - case __HYPERVISOR_event_channel_op: - regs->r8 = do_event_channel_op(regs->r14); - break; - -#ifndef CONFIG_VTI - case __HYPERVISOR_grant_table_op: - regs->r8 = do_grant_table_op(regs->r14, regs->r15, regs->r16); - break; -#endif - - case __HYPERVISOR_console_io: - regs->r8 = do_console_io(regs->r14, regs->r15, regs->r16); - break; - - default: - printf("unknown hypercall %x\n", regs->r2); - regs->r8 = (unsigned long)-1; - } - return 1; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/hyperprivop.S --- a/xen/arch/ia64/hyperprivop.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1592 +0,0 @@ -/* - * arch/ia64/kernel/hyperprivop.S - * - * Copyright (C) 2005 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ - -#include <linux/config.h> - -#include <asm/asmmacro.h> -#include <asm/kregs.h> -#include <asm/offsets.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <public/arch-ia64.h> - -#if 1 // change to 0 to turn off all fast paths -#define FAST_HYPERPRIVOPS -#define FAST_HYPERPRIVOP_CNT -#define FAST_REFLECT_CNT -//#define FAST_TICK -#define FAST_BREAK -#define FAST_ACCESS_REFLECT -#define FAST_RFI -#define FAST_SSM_I -#define FAST_PTC_GA -#undef RFI_TO_INTERRUPT // not working yet -#endif - -#ifdef CONFIG_SMP -#warning "FIXME: ptc.ga instruction requires spinlock for SMP" -#undef FAST_PTC_GA -#endif - -// FIXME: turn off for now... but NaTs may crash Xen so re-enable soon! -//#define HANDLE_AR_UNAT - -// FIXME: This is defined in include/asm-ia64/hw_irq.h but this -// doesn't appear to be include'able from assembly? -#define IA64_TIMER_VECTOR 0xef - -// Should be included from common header file (also in process.c) -// NO PSR_CLR IS DIFFERENT! (CPL) -#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT) -#define IA64_PSR_CPL0 (__IA64_UL(1) << IA64_PSR_CPL0_BIT) -// note IA64_PSR_PK removed from following, why is this necessary? -#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \ - IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \ - IA64_PSR_IT | IA64_PSR_BN) - -#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \ - IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \ - IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \ - IA64_PSR_MC | IA64_PSR_IS | \ - IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ - IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) - -// Note: not hand-scheduled for now -// Registers at entry -// r16 == cr.isr -// r17 == cr.iim -// r18 == XSI_PSR_IC_OFS -// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) -// r31 == pr -GLOBAL_ENTRY(fast_hyperprivop) -#ifndef FAST_HYPERPRIVOPS // see beginning of file - br.sptk.many dispatch_break_fault ;; -#endif - // HYPERPRIVOP_SSM_I? - // assumes domain interrupts pending, so just do it - cmp.eq p7,p6=XEN_HYPER_SSM_I,r17 -(p7) br.sptk.many hyper_ssm_i;; - - // FIXME. This algorithm gives up (goes to the slow path) if there - // are ANY interrupts pending, even if they are currently - // undeliverable. This should be improved later... - adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r20=[r20] ;; - cmp.eq p7,p0=r0,r20 -(p7) br.cond.sptk.many 1f - movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r20=[r20];; - adds r21=IA64_VCPU_IRR0_OFFSET,r20; - adds r22=IA64_VCPU_IRR0_OFFSET+8,r20;; - ld8 r23=[r21],16; ld8 r24=[r22],16;; - ld8 r21=[r21]; ld8 r22=[r22];; - or r23=r23,r24; or r21=r21,r22;; - or r20=r23,r21;; -1: // when we get to here r20=~=interrupts pending - - // HYPERPRIVOP_RFI? - cmp.eq p7,p6=XEN_HYPER_RFI,r17 -(p7) br.sptk.many hyper_rfi;; - - // HYPERPRIVOP_GET_IVR? - cmp.eq p7,p6=XEN_HYPER_GET_IVR,r17 -(p7) br.sptk.many hyper_get_ivr;; - - cmp.ne p7,p0=r20,r0 -(p7) br.spnt.many dispatch_break_fault ;; - - // HYPERPRIVOP_COVER? - cmp.eq p7,p6=XEN_HYPER_COVER,r17 -(p7) br.sptk.many hyper_cover;; - - // HYPERPRIVOP_SSM_DT? - cmp.eq p7,p6=XEN_HYPER_SSM_DT,r17 -(p7) br.sptk.many hyper_ssm_dt;; - - // HYPERPRIVOP_RSM_DT? - cmp.eq p7,p6=XEN_HYPER_RSM_DT,r17 -(p7) br.sptk.many hyper_rsm_dt;; - - // HYPERPRIVOP_GET_TPR? - cmp.eq p7,p6=XEN_HYPER_GET_TPR,r17 -(p7) br.sptk.many hyper_get_tpr;; - - // HYPERPRIVOP_SET_TPR? - cmp.eq p7,p6=XEN_HYPER_SET_TPR,r17 -(p7) br.sptk.many hyper_set_tpr;; - - // HYPERPRIVOP_EOI? - cmp.eq p7,p6=XEN_HYPER_EOI,r17 -(p7) br.sptk.many hyper_eoi;; - - // HYPERPRIVOP_SET_ITM? - cmp.eq p7,p6=XEN_HYPER_SET_ITM,r17 -(p7) br.sptk.many hyper_set_itm;; - - // HYPERPRIVOP_SET_RR? - cmp.eq p7,p6=XEN_HYPER_SET_RR,r17 -(p7) br.sptk.many hyper_set_rr;; - - // HYPERPRIVOP_GET_RR? - cmp.eq p7,p6=XEN_HYPER_GET_RR,r17 -(p7) br.sptk.many hyper_get_rr;; - - // HYPERPRIVOP_PTC_GA? - cmp.eq p7,p6=XEN_HYPER_PTC_GA,r17 -(p7) br.sptk.many hyper_ptc_ga;; - - // HYPERPRIVOP_ITC_D? - cmp.eq p7,p6=XEN_HYPER_ITC_D,r17 -(p7) br.sptk.many hyper_itc_d;; - - // HYPERPRIVOP_ITC_I? - cmp.eq p7,p6=XEN_HYPER_ITC_I,r17 -(p7) br.sptk.many hyper_itc_i;; - - // HYPERPRIVOP_THASH? - cmp.eq p7,p6=XEN_HYPER_THASH,r17 -(p7) br.sptk.many hyper_thash;; - - // if not one of the above, give up for now and do it the slow way - br.sptk.many dispatch_break_fault ;; - - -// give up for now if: ipsr.be==1, ipsr.pp==1 -// from reflect_interruption, don't need to: -// - printf first extint (debug only) -// - check for interrupt collection enabled (routine will force on) -// - set ifa (not valid for extint) -// - set iha (not valid for extint) -// - set itir (not valid for extint) -// DO need to -// - increment the HYPER_SSM_I fast_hyperprivop counter -// - set shared_mem iip to instruction after HYPER_SSM_I -// - set cr.iip to guest iva+0x3000 -// - set shared_mem ipsr to [vcpu_get_ipsr_int_state] -// be = pp = bn = 0; dt = it = rt = 1; cpl = 3 or 0; -// i = shared_mem interrupt_delivery_enabled -// ic = shared_mem interrupt_collection_enabled -// ri = instruction after HYPER_SSM_I -// all other bits unchanged from real cr.ipsr -// - set cr.ipsr (DELIVER_PSR_SET/CLEAR, don't forget cpl!) -// - set shared_mem isr: isr.ei to instr following HYPER_SSM_I -// and isr.ri to cr.isr.ri (all other bits zero) -// - cover and set shared_mem precover_ifs to cr.ifs -// ^^^ MISSED THIS FOR fast_break?? -// - set shared_mem ifs and incomplete_regframe to 0 -// - set shared_mem interrupt_delivery_enabled to 0 -// - set shared_mem interrupt_collection_enabled to 0 -// - set r31 to SHAREDINFO_ADDR -// - virtual bank switch 0 -// maybe implement later -// - verify that there really IS a deliverable interrupt pending -// - set shared_mem iva -// needs to be done but not implemented (in reflect_interruption) -// - set shared_mem iipa -// don't know for sure -// - set shared_mem unat -// r16 == cr.isr -// r17 == cr.iim -// r18 == XSI_PSR_IC -// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) -// r31 == pr -ENTRY(hyper_ssm_i) -#ifndef FAST_SSM_I - br.spnt.few dispatch_break_fault ;; -#endif - // give up for now if: ipsr.be==1, ipsr.pp==1 - mov r30=cr.ipsr;; - mov r29=cr.iip;; - extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; - cmp.ne p7,p0=r21,r0 -(p7) br.sptk.many dispatch_break_fault ;; - extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; - cmp.ne p7,p0=r21,r0 -(p7) br.sptk.many dispatch_break_fault ;; -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_I);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - // set shared_mem iip to instruction after HYPER_SSM_I - extr.u r20=r30,41,2 ;; - cmp.eq p6,p7=2,r20 ;; -(p6) mov r20=0 -(p6) adds r29=16,r29 -(p7) adds r20=1,r20 ;; - dep r30=r20,r30,41,2;; // adjust cr.ipsr.ri but don't save yet - adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r29 ;; - // set shared_mem isr - extr.u r16=r16,38,1;; // grab cr.isr.ir bit - dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) - dep r16=r20,r16,41,2 ;; // deposit cr.isr.ri - adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r16 ;; - // set cr.ipsr - mov r29=r30 ;; - movl r28=DELIVER_PSR_SET;; - movl r27=~DELIVER_PSR_CLR;; - or r29=r29,r28;; - and r29=r29,r27;; - mov cr.ipsr=r29;; - // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set) - extr.u r29=r30,IA64_PSR_CPL0_BIT,2;; - cmp.eq p6,p7=3,r29;; -(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2 -(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2 - ;; - // FOR SSM_I ONLY, also turn on psr.i and psr.ic - movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT|IA64_PSR_I|IA64_PSR_IC);; - movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);; - or r30=r30,r28;; - and r30=r30,r27;; - adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r30 ;; - // set shared_mem interrupt_delivery_enabled to 0 - // set shared_mem interrupt_collection_enabled to 0 - st8 [r18]=r0;; - // cover and set shared_mem precover_ifs to cr.ifs - // set shared_mem ifs and incomplete_regframe to 0 - cover ;; - mov r20=cr.ifs;; - adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r21]=r0 ;; - adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r0 ;; - adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r20 ;; - // leave cr.ifs alone for later rfi - // set iip to go to domain IVA break instruction vector - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22=[r22];; - adds r22=IA64_VCPU_IVA_OFFSET,r22;; - ld8 r23=[r22];; - movl r24=0x3000;; - add r24=r24,r23;; - mov cr.iip=r24;; - // OK, now all set to go except for switch to virtual bank0 - mov r30=r2; mov r29=r3;; - adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; - adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; - bsw.1;; - // FIXME?: ar.unat is not really handled correctly, - // but may not matter if the OS is NaT-clean - .mem.offset 0,0; st8.spill [r2]=r16,16; - .mem.offset 8,0; st8.spill [r3]=r17,16 ;; - .mem.offset 0,0; st8.spill [r2]=r18,16; - .mem.offset 8,0; st8.spill [r3]=r19,16 ;; - .mem.offset 0,0; st8.spill [r2]=r20,16; - .mem.offset 8,0; st8.spill [r3]=r21,16 ;; - .mem.offset 0,0; st8.spill [r2]=r22,16; - .mem.offset 8,0; st8.spill [r3]=r23,16 ;; - .mem.offset 0,0; st8.spill [r2]=r24,16; - .mem.offset 8,0; st8.spill [r3]=r25,16 ;; - .mem.offset 0,0; st8.spill [r2]=r26,16; - .mem.offset 8,0; st8.spill [r3]=r27,16 ;; - .mem.offset 0,0; st8.spill [r2]=r28,16; - .mem.offset 8,0; st8.spill [r3]=r29,16 ;; - .mem.offset 0,0; st8.spill [r2]=r30,16; - .mem.offset 8,0; st8.spill [r3]=r31,16 ;; - movl r31=XSI_IPSR;; - bsw.0 ;; - mov r2=r30; mov r3=r29;; - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r0 ;; - mov pr=r31,-1 ;; - rfi - ;; - -// reflect domain clock interrupt -// r31 == pr -// r30 == cr.ivr -// r29 == rp -GLOBAL_ENTRY(fast_tick_reflect) -#ifndef FAST_TICK // see beginning of file - br.cond.sptk.many rp;; -#endif - mov r28=IA64_TIMER_VECTOR;; - cmp.ne p6,p0=r28,r30 -(p6) br.cond.spnt.few rp;; - movl r20=THIS_CPU(cpu_info)+IA64_CPUINFO_ITM_NEXT_OFFSET;; - ld8 r26=[r20];; - mov r27=ar.itc;; - adds r27=200,r27;; // safety margin - cmp.ltu p6,p0=r26,r27 -(p6) br.cond.spnt.few rp;; - mov r17=cr.ipsr;; - // slow path if: ipsr.be==1, ipsr.pp==1 - extr.u r21=r17,IA64_PSR_BE_BIT,1 ;; - cmp.ne p6,p0=r21,r0 -(p6) br.cond.spnt.few rp;; - extr.u r21=r17,IA64_PSR_PP_BIT,1 ;; - cmp.ne p6,p0=r21,r0 -(p6) br.cond.spnt.few rp;; - // definitely have a domain tick - mov cr.eoi=r0;; - mov rp=r29;; - mov cr.itm=r26;; // ensure next tick -#ifdef FAST_REFLECT_CNT - movl r20=fast_reflect_count+((0x3000>>8)*8);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - // vcpu_pend_timer(current) - movl r18=XSI_PSR_IC;; - adds r20=XSI_ITV_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r20];; - cmp.eq p6,p0=r20,r0 // if cr.itv==0 done -(p6) br.cond.spnt.few fast_tick_reflect_done;; - tbit.nz p6,p0=r20,16;; // check itv.m (discard) bit -(p6) br.cond.spnt.few fast_tick_reflect_done;; - extr.u r27=r20,0,6 // r27 has low 6 bits of itv.vector - extr.u r26=r20,6,2;; // r26 has irr index of itv.vector - movl r19=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r19=[r19];; - adds r22=IA64_VCPU_DOMAIN_ITM_LAST_OFFSET,r19 - adds r23=IA64_VCPU_DOMAIN_ITM_OFFSET,r19;; - ld8 r24=[r22];; - ld8 r23=[r23];; - cmp.eq p6,p0=r23,r24 // skip if this tick already delivered -(p6) br.cond.spnt.few fast_tick_reflect_done;; - // set irr bit - adds r21=IA64_VCPU_IRR0_OFFSET,r19; - shl r26=r26,3;; - add r21=r21,r26;; - mov r25=1;; - shl r22=r25,r27;; - ld8 r23=[r21];; - or r22=r22,r23;; - st8 [r21]=r22;; - // set PSCB(pending_interruption)! - adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r25;; - - // if interrupted at pl0, we're done - extr.u r16=r17,IA64_PSR_CPL0_BIT,2;; - cmp.eq p6,p0=r16,r0;; -(p6) br.cond.spnt.few fast_tick_reflect_done;; - // if guest vpsr.i is off, we're done - adds r21=XSI_PSR_I_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r21=[r21];; - cmp.eq p6,p0=r21,r0 -(p6) br.cond.spnt.few fast_tick_reflect_done;; - - // OK, we have a clock tick to deliver to the active domain! - // so deliver to iva+0x3000 - // r17 == cr.ipsr - // r18 == XSI_PSR_IC - // r19 == IA64_KR(CURRENT) - // r31 == pr - mov r16=cr.isr;; - mov r29=cr.iip;; - adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r29 ;; - // set shared_mem isr - extr.u r16=r16,38,1;; // grab cr.isr.ir bit - dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) - extr.u r20=r17,41,2 ;; // get ipsr.ri - dep r16=r20,r16,41,2 ;; // deposit cr.isr.ei - adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r16 ;; - // set cr.ipsr (make sure cpl==2!) - mov r29=r17 ;; - movl r28=DELIVER_PSR_SET;; - movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; - or r29=r29,r28;; - and r29=r29,r27;; - mov cr.ipsr=r29;; - // set shared_mem ipsr (from ipsr in r17 with ipsr.ri already set) - extr.u r29=r17,IA64_PSR_CPL0_BIT,2;; - cmp.eq p6,p7=3,r29;; -(p6) dep r17=-1,r17,IA64_PSR_CPL0_BIT,2 -(p7) dep r17=0,r17,IA64_PSR_CPL0_BIT,2 - ;; - movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT);; - movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN|IA64_PSR_I|IA64_PSR_IC);; - dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;; - or r17=r17,r28;; - and r17=r17,r27;; - ld4 r16=[r18],4;; - cmp.ne p6,p0=r16,r0;; -(p6) dep r17=-1,r17,IA64_PSR_IC_BIT,1 ;; - ld4 r16=[r18],-4;; - cmp.ne p6,p0=r16,r0;; -(p6) dep r17=-1,r17,IA64_PSR_I_BIT,1 ;; - adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r17 ;; - // set shared_mem interrupt_delivery_enabled to 0 - // set shared_mem interrupt_collection_enabled to 0 - st8 [r18]=r0;; - // cover and set shared_mem precover_ifs to cr.ifs - // set shared_mem ifs and incomplete_regframe to 0 - cover ;; - mov r20=cr.ifs;; - adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r21]=r0 ;; - adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r0 ;; - adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r20 ;; - // leave cr.ifs alone for later rfi - // set iip to go to domain IVA break instruction vector - adds r22=IA64_VCPU_IVA_OFFSET,r19;; - ld8 r23=[r22];; - movl r24=0x3000;; - add r24=r24,r23;; - mov cr.iip=r24;; - // OK, now all set to go except for switch to virtual bank0 - mov r30=r2; mov r29=r3;; -#ifdef HANDLE_AR_UNAT - mov r28=ar.unat; -#endif - adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; - adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; - bsw.1;; - .mem.offset 0,0; st8.spill [r2]=r16,16; - .mem.offset 8,0; st8.spill [r3]=r17,16 ;; - .mem.offset 0,0; st8.spill [r2]=r18,16; - .mem.offset 8,0; st8.spill [r3]=r19,16 ;; - .mem.offset 0,0; st8.spill [r2]=r20,16; - .mem.offset 8,0; st8.spill [r3]=r21,16 ;; - .mem.offset 0,0; st8.spill [r2]=r22,16; - .mem.offset 8,0; st8.spill [r3]=r23,16 ;; - .mem.offset 0,0; st8.spill [r2]=r24,16; - .mem.offset 8,0; st8.spill [r3]=r25,16 ;; - .mem.offset 0,0; st8.spill [r2]=r26,16; - .mem.offset 8,0; st8.spill [r3]=r27,16 ;; - .mem.offset 0,0; st8.spill [r2]=r28,16; - .mem.offset 8,0; st8.spill [r3]=r29,16 ;; - .mem.offset 0,0; st8.spill [r2]=r30,16; - .mem.offset 8,0; st8.spill [r3]=r31,16 ;; -#ifdef HANDLE_AR_UNAT - // bank0 regs have no NaT bit, so ensure they are NaT clean - mov r16=r0; mov r17=r0; mov r18=r0; mov r19=r0; - mov r20=r0; mov r21=r0; mov r22=r0; mov r23=r0; - mov r24=r0; mov r25=r0; mov r26=r0; mov r27=r0; - mov r28=r0; mov r29=r0; mov r30=r0; movl r31=XSI_IPSR;; -#endif - bsw.0 ;; - mov r2=r30; mov r3=r29;; -#ifdef HANDLE_AR_UNAT - mov ar.unat=r28; -#endif - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r0 ;; -fast_tick_reflect_done: - mov pr=r31,-1 ;; - rfi -END(fast_tick_reflect) - -// reflect domain breaks directly to domain -// r16 == cr.isr -// r17 == cr.iim -// r18 == XSI_PSR_IC -// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) -// r31 == pr -GLOBAL_ENTRY(fast_break_reflect) -#ifndef FAST_BREAK // see beginning of file - br.sptk.many dispatch_break_fault ;; -#endif - mov r30=cr.ipsr;; - mov r29=cr.iip;; - extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; - cmp.ne p7,p0=r21,r0 ;; -(p7) br.spnt.few dispatch_break_fault ;; - extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; - cmp.ne p7,p0=r21,r0 ;; -(p7) br.spnt.few dispatch_break_fault ;; -#if 1 /* special handling in case running on simulator */ - movl r20=first_break;; - ld4 r23=[r20];; - movl r21=0x80001; - movl r22=0x80002;; - cmp.ne p7,p0=r23,r0;; -(p7) br.spnt.few dispatch_break_fault ;; - cmp.eq p7,p0=r21,r17; -(p7) br.spnt.few dispatch_break_fault ;; - cmp.eq p7,p0=r22,r17; -(p7) br.spnt.few dispatch_break_fault ;; -#endif - movl r20=0x2c00; - // save iim in shared_info - adds r21=XSI_IIM_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r17;; - // fall through - - -// reflect to domain ivt+r20 -// sets up isr,iip,ipsr,ifs (FIXME: do iipa too) -// r16 == cr.isr -// r18 == XSI_PSR_IC -// r20 == offset into ivt -// r29 == iip -// r30 == ipsr -// r31 == pr -ENTRY(fast_reflect) -#ifdef FAST_REFLECT_CNT - movl r22=fast_reflect_count; - shr r23=r20,5;; - add r22=r22,r23;; - ld8 r21=[r22];; - adds r21=1,r21;; - st8 [r22]=r21;; -#endif - // save iip in shared_info (DON'T POINT TO NEXT INSTRUCTION!) - adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r29;; - // set shared_mem isr - adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r16 ;; - // set cr.ipsr - mov r29=r30 ;; - movl r28=DELIVER_PSR_SET;; - movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; - or r29=r29,r28;; - and r29=r29,r27;; - mov cr.ipsr=r29;; - // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set) - extr.u r29=r30,IA64_PSR_CPL0_BIT,2;; - cmp.eq p6,p7=3,r29;; -(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2 -(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2 - ;; - movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT);; - movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);; - or r30=r30,r28;; - and r30=r30,r27;; - // also set shared_mem ipsr.i and ipsr.ic appropriately - ld8 r24=[r18];; - extr.u r22=r24,32,32 - cmp4.eq p6,p7=r24,r0;; -(p6) dep r30=0,r30,IA64_PSR_IC_BIT,1 -(p7) dep r30=-1,r30,IA64_PSR_IC_BIT,1 ;; - cmp4.eq p6,p7=r22,r0;; -(p6) dep r30=0,r30,IA64_PSR_I_BIT,1 -(p7) dep r30=-1,r30,IA64_PSR_I_BIT,1 ;; - adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r30 ;; - // set shared_mem interrupt_delivery_enabled to 0 - // set shared_mem interrupt_collection_enabled to 0 - st8 [r18]=r0;; - // cover and set shared_mem precover_ifs to cr.ifs - // set shared_mem ifs and incomplete_regframe to 0 - cover ;; - mov r24=cr.ifs;; - adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r21]=r0 ;; - adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r0 ;; - adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r24 ;; - // vpsr.i = vpsr.ic = 0 on delivery of interruption - st8 [r18]=r0;; - // FIXME: need to save iipa and isr to be arch-compliant - // set iip to go to domain IVA break instruction vector - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22=[r22];; - adds r22=IA64_VCPU_IVA_OFFSET,r22;; - ld8 r23=[r22];; - add r20=r20,r23;; - mov cr.iip=r20;; - // OK, now all set to go except for switch to virtual bank0 - mov r30=r2; mov r29=r3;; -#ifdef HANDLE_AR_UNAT - mov r28=ar.unat; -#endif - adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; - adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; - bsw.1;; - .mem.offset 0,0; st8.spill [r2]=r16,16; - .mem.offset 8,0; st8.spill [r3]=r17,16 ;; - .mem.offset 0,0; st8.spill [r2]=r18,16; - .mem.offset 8,0; st8.spill [r3]=r19,16 ;; - .mem.offset 0,0; st8.spill [r2]=r20,16; - .mem.offset 8,0; st8.spill [r3]=r21,16 ;; - .mem.offset 0,0; st8.spill [r2]=r22,16; - .mem.offset 8,0; st8.spill [r3]=r23,16 ;; - .mem.offset 0,0; st8.spill [r2]=r24,16; - .mem.offset 8,0; st8.spill [r3]=r25,16 ;; - .mem.offset 0,0; st8.spill [r2]=r26,16; - .mem.offset 8,0; st8.spill [r3]=r27,16 ;; - .mem.offset 0,0; st8.spill [r2]=r28,16; - .mem.offset 8,0; st8.spill [r3]=r29,16 ;; - .mem.offset 0,0; st8.spill [r2]=r30,16; - .mem.offset 8,0; st8.spill [r3]=r31,16 ;; -#ifdef HANDLE_AR_UNAT - // bank0 regs have no NaT bit, so ensure they are NaT clean - mov r16=r0; mov r17=r0; mov r18=r0; mov r19=r0; - mov r20=r0; mov r21=r0; mov r22=r0; mov r23=r0; - mov r24=r0; mov r25=r0; mov r26=r0; mov r27=r0; - mov r28=r0; mov r29=r0; mov r30=r0; movl r31=XSI_IPSR;; -#endif - movl r31=XSI_IPSR;; - bsw.0 ;; - mov r2=r30; mov r3=r29;; -#ifdef HANDLE_AR_UNAT - mov ar.unat=r28; -#endif - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r0 ;; - mov pr=r31,-1 ;; - rfi - ;; - -// reflect access faults (0x2400,0x2800,0x5300) directly to domain -// r16 == isr -// r17 == ifa -// r19 == reflect number (only pass-thru to dispatch_reflection) -// r20 == offset into ivt -// r31 == pr -GLOBAL_ENTRY(fast_access_reflect) -#ifndef FAST_ACCESS_REFLECT // see beginning of file - br.spnt.few dispatch_reflection ;; -#endif - mov r30=cr.ipsr;; - mov r29=cr.iip;; - extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; - cmp.ne p7,p0=r21,r0 -(p7) br.spnt.few dispatch_reflection ;; - extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; - cmp.ne p7,p0=r21,r0 -(p7) br.spnt.few dispatch_reflection ;; - extr.u r21=r30,IA64_PSR_CPL0_BIT,2 ;; - cmp.eq p7,p0=r21,r0 -(p7) br.spnt.few dispatch_reflection ;; - movl r18=XSI_PSR_IC;; - ld8 r21=[r18];; - cmp.eq p7,p0=r0,r21 -(p7) br.spnt.few dispatch_reflection ;; - // set shared_mem ifa, FIXME: should we validate it? - mov r17=cr.ifa;; - adds r21=XSI_IFA_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r17 ;; - // get rr[ifa] and save to itir in shared memory (extra bits ignored) - shr.u r22=r17,61 - adds r23=XSI_ITIR_OFS-XSI_PSR_IC_OFS,r18 - adds r21=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; - shladd r22=r22,3,r21;; - ld8 r22=[r22];; - st8 [r23]=r22;; - br.cond.sptk.many fast_reflect;; - - -// ensure that, if giving up, registers at entry to fast_hyperprivop unchanged -ENTRY(hyper_rfi) -#ifndef FAST_RFI - br.spnt.few dispatch_break_fault ;; -#endif - // if no interrupts pending, proceed - mov r30=r0 - cmp.eq p7,p0=r20,r0 -(p7) br.sptk.many 1f - ;; - adds r20=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r21=[r20];; // r21 = vcr.ipsr - extr.u r22=r21,IA64_PSR_I_BIT,1 ;; - mov r30=r22 - // r30 determines whether we might deliver an immediate extint -1: - adds r20=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r21=[r20];; // r21 = vcr.ipsr - extr.u r22=r21,IA64_PSR_BE_BIT,1 ;; - // if turning on psr.be, give up for now and do it the slow way - cmp.ne p7,p0=r22,r0 -(p7) br.spnt.few dispatch_break_fault ;; - // if (!(vpsr.dt && vpsr.rt && vpsr.it)), do it the slow way - movl r20=(IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_IT);; - and r22=r20,r21 - ;; - cmp.ne p7,p0=r22,r20 -(p7) br.spnt.few dispatch_break_fault ;; - // if was in metaphys mode, do it the slow way (FIXME later?) - adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r20=[r20];; - cmp.ne p7,p0=r20,r0 -(p7) br.spnt.few dispatch_break_fault ;; - // if domain hasn't already done virtual bank switch - // do it the slow way (FIXME later?) -#if 0 - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r20=[r20];; - cmp.eq p7,p0=r20,r0 -(p7) br.spnt.few dispatch_break_fault ;; -#endif - // validate vcr.iip, if in Xen range, do it the slow way - adds r20=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r22=[r20];; - movl r23=XEN_VIRT_SPACE_LOW - movl r24=XEN_VIRT_SPACE_HIGH ;; - cmp.ltu p0,p7=r22,r23 ;; // if !(iip<low) && -(p7) cmp.geu p0,p7=r22,r24 ;; // !(iip>=high) -(p7) br.spnt.few dispatch_break_fault ;; -#ifndef RFI_TO_INTERRUPT // see beginning of file - cmp.ne p6,p0=r30,r0 -(p6) br.cond.spnt.few dispatch_break_fault ;; -#endif - -1: // OK now, let's do an rfi. -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RFI);; - ld8 r23=[r20];; - adds r23=1,r23;; - st8 [r20]=r23;; -#endif -#ifdef RFI_TO_INTERRUPT - // maybe do an immediate interrupt delivery? - cmp.ne p6,p0=r30,r0 -(p6) br.cond.spnt.few rfi_check_extint;; -#endif - -just_do_rfi: - // r18=&vpsr.i|vpsr.ic, r21==vpsr, r22=vcr.iip - mov cr.iip=r22;; - adds r20=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r0 ;; - adds r20=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r20];; - dep r20=0,r20,38,25;; // ensure ifs has no reserved bits set - mov cr.ifs=r20 ;; - // ipsr.cpl == (vcr.ipsr.cpl == 0) 2 : 3; - dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;; - // vpsr.i = vcr.ipsr.i; vpsr.ic = vcr.ipsr.ic - mov r19=r0 ;; - extr.u r23=r21,IA64_PSR_I_BIT,1 ;; - cmp.ne p7,p6=r23,r0 ;; - // not done yet -(p7) dep r19=-1,r19,32,1 - extr.u r23=r21,IA64_PSR_IC_BIT,1 ;; - cmp.ne p7,p6=r23,r0 ;; -(p7) dep r19=-1,r19,0,1 ;; - st8 [r18]=r19 ;; - // force on psr.ic, i, dt, rt, it, bn - movl r20=(IA64_PSR_I|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_IT|IA64_PSR_BN) - ;; - or r21=r21,r20 - ;; - mov cr.ipsr=r21 - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r21=[r20];; - cmp.ne p7,p0=r21,r0 // domain already did "bank 1 switch?" -(p7) br.cond.spnt.few 1f; - // OK, now all set to go except for switch to virtual bank1 - mov r22=1;; st4 [r20]=r22; - mov r30=r2; mov r29=r3;; - adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; - adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; - bsw.1;; - // FIXME?: ar.unat is not really handled correctly, - // but may not matter if the OS is NaT-clean - .mem.offset 0,0; ld8.fill r16=[r2],16 ; - .mem.offset 8,0; ld8.fill r17=[r3],16 ;; - .mem.offset 0,0; ld8.fill r18=[r2],16 ; - .mem.offset 0,0; ld8.fill r19=[r3],16 ;; - .mem.offset 8,0; ld8.fill r20=[r2],16 ; - .mem.offset 8,0; ld8.fill r21=[r3],16 ;; - .mem.offset 8,0; ld8.fill r22=[r2],16 ; - .mem.offset 8,0; ld8.fill r23=[r3],16 ;; - .mem.offset 8,0; ld8.fill r24=[r2],16 ; - .mem.offset 8,0; ld8.fill r25=[r3],16 ;; - .mem.offset 8,0; ld8.fill r26=[r2],16 ; - .mem.offset 8,0; ld8.fill r27=[r3],16 ;; - .mem.offset 8,0; ld8.fill r28=[r2],16 ; - .mem.offset 8,0; ld8.fill r29=[r3],16 ;; - .mem.offset 8,0; ld8.fill r30=[r2],16 ; - .mem.offset 8,0; ld8.fill r31=[r3],16 ;; - bsw.0 ;; - mov r2=r30; mov r3=r29;; -1: mov pr=r31,-1 - ;; - rfi - ;; - -#ifdef RFI_TO_INTERRUPT -GLOBAL_ENTRY(rfi_check_extint) - //br.sptk.many dispatch_break_fault ;; - - // r18=&vpsr.i|vpsr.ic, r21==vpsr, r22=vcr.iip - // make sure none of these get trashed in case going to just_do_rfi - movl r30=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r30=[r30];; - adds r24=IA64_VCPU_INSVC3_OFFSET,r30;; - mov r25=192 - adds r16=IA64_VCPU_IRR3_OFFSET,r30;; - ld8 r23=[r16];; - cmp.eq p6,p0=r23,r0;; -(p6) adds r16=-8,r16;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r16];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r16=-8,r16;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r16];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r16=-8,r16;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r16];; -(p6) cmp.eq p6,p0=r23,r0;; - cmp.eq p6,p0=r23,r0 -(p6) br.cond.spnt.few just_do_rfi; // this is actually an error - // r16 points to non-zero element of irr, r23 has value - // r24 points to corr element of insvc, r25 has elt*64 - ld8 r26=[r24];; - cmp.geu p6,p0=r26,r23 -(p6) br.cond.spnt.many just_do_rfi; - - // not masked by insvc, get vector number - shr.u r26=r23,1;; - or r26=r23,r26;; - shr.u r27=r26,2;; - or r26=r26,r27;; - shr.u r27=r26,4;; - or r26=r26,r27;; - shr.u r27=r26,8;; - or r26=r26,r27;; - shr.u r27=r26,16;; - or r26=r26,r27;; - shr.u r27=r26,32;; - or r26=r26,r27;; - andcm r26=0xffffffffffffffff,r26;; - popcnt r26=r26;; - sub r26=63,r26;; - // r26 now contains the bit index (mod 64) - mov r27=1;; - shl r27=r27,r26;; - // r27 now contains the (within the proper word) bit mask - add r26=r25,r26 - // r26 now contains the vector [0..255] - adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r20] ;; - extr.u r28=r20,16,1 - extr.u r29=r20,4,4 ;; - cmp.ne p6,p0=r28,r0 // if tpr.mmi is set, just rfi -(p6) br.cond.spnt.few just_do_rfi;; - shl r29=r29,4;; - adds r29=15,r29;; - cmp.ge p6,p0=r29,r26 // if tpr masks interrupt, just rfi -(p6) br.cond.spnt.few just_do_rfi;; - -// this doesn't work yet (dies early after getting to user mode) -// but happens relatively infrequently, so fix it later. -// NOTE that these will be counted incorrectly for now (for privcnt output) -GLOBAL_ENTRY(rfi_with_interrupt) -#if 1 - br.sptk.many dispatch_break_fault ;; -#endif - - // OK, have an unmasked vector, so deliver extint to vcr.iva+0x3000 - // r18 == XSI_PSR_IC - // r21 == vipsr (ipsr in shared_mem) - // r30 == IA64_KR(CURRENT) - // r31 == pr - mov r17=cr.ipsr;; - mov r16=cr.isr;; - // set shared_mem isr - extr.u r16=r16,38,1;; // grab cr.isr.ir bit - dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero) - extr.u r20=r21,41,2 ;; // get v(!)psr.ri - dep r16=r20,r16,41,2 ;; // deposit cr.isr.ei - adds r22=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r22]=r16 ;; - // set cr.ipsr (make sure cpl==2!) - mov r29=r17 ;; - movl r28=DELIVER_PSR_SET;; - movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);; - or r29=r29,r28;; - and r29=r29,r27;; - mov cr.ipsr=r29;; - // v.ipsr and v.iip are already set (and v.iip validated) as rfi target - // set shared_mem interrupt_delivery_enabled to 0 - // set shared_mem interrupt_collection_enabled to 0 - st8 [r18]=r0;; - // cover and set shared_mem precover_ifs to cr.ifs - // set shared_mem ifs and incomplete_regframe to 0 -#if 0 - cover ;; - mov r20=cr.ifs;; - adds r22=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r22]=r0 ;; - adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r22]=r0 ;; - adds r22=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r22]=r20 ;; - // leave cr.ifs alone for later rfi -#else - adds r22=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r22]=r0 ;; - adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r22];; - st8 [r22]=r0 ;; - adds r22=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r22]=r20 ;; -#endif - // set iip to go to domain IVA break instruction vector - adds r22=IA64_VCPU_IVA_OFFSET,r30;; - ld8 r23=[r22];; - movl r24=0x3000;; - add r24=r24,r23;; - mov cr.iip=r24;; -#if 0 - // OK, now all set to go except for switch to virtual bank0 - mov r30=r2; mov r29=r3;; - adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; - adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; - bsw.1;; - // FIXME: need to handle ar.unat! - .mem.offset 0,0; st8.spill [r2]=r16,16; - .mem.offset 8,0; st8.spill [r3]=r17,16 ;; - .mem.offset 0,0; st8.spill [r2]=r18,16; - .mem.offset 8,0; st8.spill [r3]=r19,16 ;; - .mem.offset 0,0; st8.spill [r2]=r20,16; - .mem.offset 8,0; st8.spill [r3]=r21,16 ;; - .mem.offset 0,0; st8.spill [r2]=r22,16; - .mem.offset 8,0; st8.spill [r3]=r23,16 ;; - .mem.offset 0,0; st8.spill [r2]=r24,16; - .mem.offset 8,0; st8.spill [r3]=r25,16 ;; - .mem.offset 0,0; st8.spill [r2]=r26,16; - .mem.offset 8,0; st8.spill [r3]=r27,16 ;; - .mem.offset 0,0; st8.spill [r2]=r28,16; - .mem.offset 8,0; st8.spill [r3]=r29,16 ;; - .mem.offset 0,0; st8.spill [r2]=r30,16; - .mem.offset 8,0; st8.spill [r3]=r31,16 ;; - movl r31=XSI_IPSR;; - bsw.0 ;; - mov r2=r30; mov r3=r29;; -#else - bsw.1;; - movl r31=XSI_IPSR;; - bsw.0 ;; -#endif - adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;; - st4 [r20]=r0 ;; - mov pr=r31,-1 ;; - rfi -#endif // RFI_TO_INTERRUPT - -ENTRY(hyper_cover) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_COVER);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r24=cr.ipsr - mov r25=cr.iip;; - // skip test for vpsr.ic.. it's a prerequisite for hyperprivops - cover ;; - adds r20=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; - mov r30=cr.ifs;; - adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 - ld4 r21=[r20] ;; - cmp.eq p6,p7=r21,r0 ;; -(p6) st8 [r22]=r30;; -(p7) st4 [r20]=r0;; - mov cr.ifs=r0;; - // adjust return address to skip over break instruction - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; - -// return from metaphysical mode (meta=1) to virtual mode (meta=0) -ENTRY(hyper_ssm_dt) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_DT);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r24=cr.ipsr - mov r25=cr.iip;; - adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r21=[r20];; - cmp.eq p7,p0=r21,r0 // meta==0? -(p7) br.spnt.many 1f ;; // already in virtual mode - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22=[r22];; - adds r22=IA64_VCPU_META_SAVED_RR0_OFFSET,r22;; - ld4 r23=[r22];; - mov rr[r0]=r23;; - srlz.i;; - st4 [r20]=r0 ;; - // adjust return address to skip over break instruction -1: extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; - -// go to metaphysical mode (meta=1) from virtual mode (meta=0) -ENTRY(hyper_rsm_dt) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RSM_DT);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r24=cr.ipsr - mov r25=cr.iip;; - adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;; - ld4 r21=[r20];; - cmp.ne p7,p0=r21,r0 // meta==0? -(p7) br.spnt.many 1f ;; // already in metaphysical mode - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22=[r22];; - adds r22=IA64_VCPU_META_RR0_OFFSET,r22;; - ld4 r23=[r22];; - mov rr[r0]=r23;; - srlz.i;; - adds r21=1,r0 ;; - st4 [r20]=r21 ;; - // adjust return address to skip over break instruction -1: extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; - -ENTRY(hyper_get_tpr) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_TPR);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r24=cr.ipsr - mov r25=cr.iip;; - adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r8=[r20];; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_get_tpr) - -// if we get to here, there are no interrupts pending so we -// can change virtual tpr to any value without fear of provoking -// (or accidentally missing) delivering an interrupt -ENTRY(hyper_set_tpr) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_TPR);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r24=cr.ipsr - mov r25=cr.iip;; - movl r27=0xff00;; - adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; - andcm r8=r8,r27;; - st8 [r20]=r8;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_set_tpr) - -ENTRY(hyper_get_ivr) -#ifdef FAST_HYPERPRIVOP_CNT - movl r22=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_IVR);; - ld8 r21=[r22];; - adds r21=1,r21;; - st8 [r22]=r21;; -#endif - mov r8=15;; - // when we get to here r20=~=interrupts pending - cmp.eq p7,p0=r20,r0;; -(p7) adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;; -(p7) st4 [r20]=r0;; -(p7) br.spnt.many 1f ;; - movl r30=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r30=[r30];; - adds r24=IA64_VCPU_INSVC3_OFFSET,r30;; - mov r25=192 - adds r22=IA64_VCPU_IRR3_OFFSET,r30;; - ld8 r23=[r22];; - cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) adds r24=-8,r24;; -(p6) adds r25=-64,r25;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; - cmp.eq p6,p0=r23,r0 -(p6) br.cond.spnt.few 1f; // this is actually an error - // r22 points to non-zero element of irr, r23 has value - // r24 points to corr element of insvc, r25 has elt*64 - ld8 r26=[r24];; - cmp.geu p6,p0=r26,r23 -(p6) br.cond.spnt.many 1f; - // not masked by insvc, get vector number - shr.u r26=r23,1;; - or r26=r23,r26;; - shr.u r27=r26,2;; - or r26=r26,r27;; - shr.u r27=r26,4;; - or r26=r26,r27;; - shr.u r27=r26,8;; - or r26=r26,r27;; - shr.u r27=r26,16;; - or r26=r26,r27;; - shr.u r27=r26,32;; - or r26=r26,r27;; - andcm r26=0xffffffffffffffff,r26;; - popcnt r26=r26;; - sub r26=63,r26;; - // r26 now contains the bit index (mod 64) - mov r27=1;; - shl r27=r27,r26;; - // r27 now contains the (within the proper word) bit mask - add r26=r25,r26 - // r26 now contains the vector [0..255] - adds r20=XSI_TPR_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r20] ;; - extr.u r28=r20,16,1 - extr.u r29=r20,4,4 ;; - cmp.ne p6,p0=r28,r0 // if tpr.mmi is set, return SPURIOUS -(p6) br.cond.spnt.few 1f; - shl r29=r29,4;; - adds r29=15,r29;; - cmp.ge p6,p0=r29,r26 -(p6) br.cond.spnt.few 1f; - // OK, have an unmasked vector to process/return - ld8 r25=[r24];; - or r25=r25,r27;; - st8 [r24]=r25;; - ld8 r25=[r22];; - andcm r25=r25,r27;; - st8 [r22]=r25;; - mov r8=r26;; - // if its a clock tick, remember itm to avoid delivering it twice - adds r20=XSI_ITV_OFS-XSI_PSR_IC_OFS,r18 ;; - ld8 r20=[r20];; - extr.u r20=r20,0,8;; - cmp.eq p6,p0=r20,r8 - adds r22=IA64_VCPU_DOMAIN_ITM_LAST_OFFSET,r30 - adds r23=IA64_VCPU_DOMAIN_ITM_OFFSET,r30;; - ld8 r23=[r23];; -(p6) st8 [r22]=r23;; - // all done -1: mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_get_ivr) - -ENTRY(hyper_eoi) - // when we get to here r20=~=interrupts pending - cmp.ne p7,p0=r20,r0 -(p7) br.spnt.many dispatch_break_fault ;; -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_EOI);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22=[r22];; - adds r22=IA64_VCPU_INSVC3_OFFSET,r22;; - ld8 r23=[r22];; - cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; -(p6) adds r22=-8,r22;; -(p6) ld8 r23=[r22];; -(p6) cmp.eq p6,p0=r23,r0;; - cmp.eq p6,p0=r23,r0 -(p6) br.cond.spnt.few 1f; // this is actually an error - // r22 points to non-zero element of insvc, r23 has value - shr.u r24=r23,1;; - or r24=r23,r24;; - shr.u r25=r24,2;; - or r24=r24,r25;; - shr.u r25=r24,4;; - or r24=r24,r25;; - shr.u r25=r24,8;; - or r24=r24,r25;; - shr.u r25=r24,16;; - or r24=r24,r25;; - shr.u r25=r24,32;; - or r24=r24,r25;; - andcm r24=0xffffffffffffffff,r24;; - popcnt r24=r24;; - sub r24=63,r24;; - // r24 now contains the bit index - mov r25=1;; - shl r25=r25,r24;; - andcm r23=r23,r25;; - st8 [r22]=r23;; -1: mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_eoi) - -ENTRY(hyper_set_itm) - // when we get to here r20=~=interrupts pending - cmp.ne p7,p0=r20,r0 -(p7) br.spnt.many dispatch_break_fault ;; -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_ITM);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - movl r20=THIS_CPU(cpu_info)+IA64_CPUINFO_ITM_NEXT_OFFSET;; - ld8 r21=[r20];; - movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r20=[r20];; - adds r20=IA64_VCPU_DOMAIN_ITM_OFFSET,r20;; - st8 [r20]=r8;; - cmp.geu p6,p0=r21,r8;; -(p6) mov r21=r8;; - // now "safe set" cr.itm=r21 - mov r23=100;; -2: mov cr.itm=r21;; - srlz.d;; - mov r22=ar.itc ;; - cmp.leu p6,p0=r21,r22;; - add r21=r21,r23;; - shl r23=r23,1;; -(p6) br.cond.spnt.few 2b;; -1: mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_set_itm) - -ENTRY(hyper_get_rr) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_GET_RR);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - extr.u r25=r8,61,3;; - adds r20=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; - shl r25=r25,3;; - add r20=r20,r25;; - ld8 r8=[r20];; -1: mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_get_rr) - -ENTRY(hyper_set_rr) - extr.u r25=r8,61,3;; - cmp.leu p7,p0=7,r25 // punt on setting rr7 -(p7) br.spnt.many dispatch_break_fault ;; -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SET_RR);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - extr.u r26=r9,8,24 // r26 = r9.rid - movl r20=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r20=[r20];; - adds r21=IA64_VCPU_STARTING_RID_OFFSET,r20;; - ld4 r22=[r21];; - adds r21=IA64_VCPU_ENDING_RID_OFFSET,r20;; - ld4 r23=[r21];; - adds r24=IA64_VCPU_META_SAVED_RR0_OFFSET,r20;; - add r22=r26,r22;; - cmp.geu p6,p0=r22,r23 // if r9.rid + starting_rid >= ending_rid -(p6) br.cond.spnt.few 1f; // this is an error, but just ignore/return - // r21=starting_rid - adds r20=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; - shl r25=r25,3;; - add r20=r20,r25;; - st8 [r20]=r9;; // store away exactly what was passed - // but adjust value actually placed in rr[r8] - // r22 contains adjusted rid, "mangle" it (see regionreg.c) - // and set ps to PAGE_SHIFT and ve to 1 - extr.u r27=r22,0,8 - extr.u r28=r22,8,8 - extr.u r29=r22,16,8;; - dep.z r23=PAGE_SHIFT,2,6;; - dep r23=-1,r23,0,1;; // mangling is swapping bytes 1 & 3 - dep r23=r27,r23,24,8;; - dep r23=r28,r23,16,8;; - dep r23=r29,r23,8,8 - cmp.eq p6,p0=r25,r0;; // if rr0, save for metaphysical -(p6) st4 [r24]=r23 - mov rr[r8]=r23;; - // done, mosey on back -1: mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_set_rr) - -// this routine was derived from optimized assembly output from -// vcpu_thash so it is dense and difficult to read but it works -// On entry: -// r18 == XSI_PSR_IC -// r31 == pr -GLOBAL_ENTRY(hyper_thash) -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_THASH);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - shr.u r20 = r8, 61 - addl r25 = 1, r0 - movl r17 = 0xe000000000000000 - ;; - and r21 = r17, r8 // VHPT_Addr1 - ;; - shladd r28 = r20, 3, r18 - adds r19 = XSI_PTA_OFS-XSI_PSR_IC_OFS, r18 - ;; - adds r27 = XSI_RR0_OFS-XSI_PSR_IC_OFS, r28 - addl r28 = 32767, r0 - ld8 r24 = [r19] // pta - ;; - ld8 r23 = [r27] // rrs[vadr>>61] - extr.u r26 = r24, 2, 6 - ;; - extr.u r22 = r23, 2, 6 - shl r30 = r25, r26 - ;; - shr.u r19 = r8, r22 - shr.u r29 = r24, 15 - ;; - adds r17 = -1, r30 - ;; - shladd r27 = r19, 3, r0 - extr.u r26 = r17, 15, 46 - ;; - andcm r24 = r29, r26 - and r19 = r28, r27 - shr.u r25 = r27, 15 - ;; - and r23 = r26, r25 - ;; - or r22 = r24, r23 - ;; - dep.z r20 = r22, 15, 46 - ;; - or r16 = r20, r21 - ;; - or r8 = r19, r16 - // done, update iip/ipsr to next instruction - mov r24=cr.ipsr - mov r25=cr.iip;; - extr.u r26=r24,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r25=16,r25 -(p7) adds r26=1,r26 - ;; - dep r24=r26,r24,41,2 - ;; - mov cr.ipsr=r24 - mov cr.iip=r25 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_thash) - -ENTRY(hyper_ptc_ga) -#ifndef FAST_PTC_GA - br.spnt.few dispatch_break_fault ;; -#endif - // FIXME: validate not flushing Xen addresses -#ifdef FAST_HYPERPRIVOP_CNT - movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_PTC_GA);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif - mov r28=r8 - extr.u r19=r9,2,6 // addr_range=1<<((r9&0xfc)>>2) - mov r20=1 - shr.u r24=r8,61 - addl r27=56,r0 // PAGE_SHIFT<<2 (for ptc.ga) - movl r26=0x8000000000000000 // INVALID_TI_TAG - mov r30=ar.lc - ;; - shl r19=r20,r19 - cmp.eq p7,p0=7,r24 -(p7) br.spnt.many dispatch_break_fault ;; // slow way for rr7 - ;; - cmp.le p7,p0=r19,r0 // skip flush if size<=0 -(p7) br.cond.dpnt 2f ;; - extr.u r24=r19,0,PAGE_SHIFT - shr.u r23=r19,PAGE_SHIFT ;; // repeat loop for n pages - cmp.ne p7,p0=r24,r0 ;; -(p7) adds r23=1,r23 ;; // n_pages<size<n_pages+1? extra iter - mov ar.lc=r23 - movl r29=PAGE_SIZE;; -1: - thash r25=r28 ;; - adds r25=16,r25 ;; - ld8 r24=[r25] ;; - // FIXME: should check if tag matches, not just blow it away - or r24=r26,r24 ;; // vhpt_entry->ti_tag = 1 - st8 [r25]=r24 - ptc.ga r28,r27 ;; - srlz.i ;; - add r28=r29,r28 - br.cloop.sptk.few 1b - ;; -2: - mov ar.lc=r30 ;; - mov r29=cr.ipsr - mov r30=cr.iip;; - movl r27=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r27=[r27];; - adds r25=IA64_VCPU_DTLB_OFFSET,r27 - adds r26=IA64_VCPU_ITLB_OFFSET,r27;; - ld8 r24=[r25] - ld8 r27=[r26] ;; - and r24=-2,r24 - and r27=-2,r27 ;; - st8 [r25]=r24 // set 1-entry i/dtlb as not present - st8 [r26]=r27 ;; - // increment to point to next instruction - extr.u r26=r29,41,2 ;; - cmp.eq p6,p7=2,r26 ;; -(p6) mov r26=0 -(p6) adds r30=16,r30 -(p7) adds r26=1,r26 - ;; - dep r29=r26,r29,41,2 - ;; - mov cr.ipsr=r29 - mov cr.iip=r30 - mov pr=r31,-1 ;; - rfi - ;; -END(hyper_ptc_ga) - -ENTRY(hyper_itc_d) - br.spnt.many dispatch_break_fault ;; -END(hyper_itc_d) - -ENTRY(hyper_itc_i) - br.spnt.many dispatch_break_fault ;; -END(hyper_itc_i) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/idle0_task.c --- a/xen/arch/ia64/idle0_task.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,58 +0,0 @@ -#include <xen/config.h> -#include <xen/sched.h> -#include <asm/desc.h> - -#define INIT_MM(name) \ -{ \ - .pgd = swapper_pg_dir, \ - .mm_users = ATOMIC_INIT(2), \ - .mm_count = ATOMIC_INIT(1), \ - .page_table_lock = SPIN_LOCK_UNLOCKED, \ - .mmlist = LIST_HEAD_INIT(name.mmlist), \ -} - -#define IDLE0_EXEC_DOMAIN(_ed,_d) \ -{ \ - processor: 0, \ - mm: 0, \ - thread: INIT_THREAD, \ - domain: (_d) \ -} - -#define IDLE0_DOMAIN(_t) \ -{ \ - domain_id: IDLE_DOMAIN_ID, \ - domain_flags:DOMF_idle_domain, \ - refcnt: ATOMIC_INIT(1) \ -} - -struct mm_struct init_mm = INIT_MM(init_mm); -EXPORT_SYMBOL(init_mm); - -struct domain idle0_domain = IDLE0_DOMAIN(idle0_domain); -#if 0 -struct vcpu idle0_vcpu = IDLE0_EXEC_DOMAIN(idle0_vcpu, - &idle0_domain); -#endif - - -/* - * Initial task structure. - * - * We need to make sure that this is properly aligned due to the way process stacks are - * handled. This is done by having a special ".data.init_task" section... - */ -union { - struct { - struct domain task; - } s; - unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)]; -} init_task_mem asm ("init_task") __attribute__((section(".data.init_task"))); -// = {{ - ; -//.task = IDLE0_EXEC_DOMAIN(init_task_mem.s.task,&idle0_domain), -//}; -//}; - -EXPORT_SYMBOL(init_task); - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/irq.c --- a/xen/arch/ia64/irq.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1503 +0,0 @@ -/* - * linux/arch/ia64/kernel/irq.c - * - * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar - * - * This file contains the code used by various IRQ handling routines: - * asking for different IRQ's should be done through these routines - * instead of just grabbing them. Thus setups with different IRQ numbers - * shouldn't result in any weird surprises, and installing new handlers - * should be easier. - * - * Copyright (C) Ashok Raj<ashok.raj@xxxxxxxxx>, Intel Corporation 2004 - * - * 4/14/2004: Added code to handle cpu migration and do safe irq - * migration without lossing interrupts for iosapic - * architecture. - */ - -/* - * (mostly architecture independent, will move to kernel/irq.c in 2.5.) - * - * IRQs are in fact implemented a bit like signal handlers for the kernel. - * Naturally it's not a 1:1 relation, but there are similarities. - */ - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/module.h> -#ifndef XEN -#include <linux/signal.h> -#endif -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/slab.h> -#ifndef XEN -#include <linux/random.h> -#include <linux/cpu.h> -#endif -#include <linux/ctype.h> -#ifndef XEN -#include <linux/smp_lock.h> -#endif -#include <linux/init.h> -#ifndef XEN -#include <linux/kernel_stat.h> -#endif -#include <linux/irq.h> -#ifndef XEN -#include <linux/proc_fs.h> -#endif -#include <linux/seq_file.h> -#ifndef XEN -#include <linux/kallsyms.h> -#include <linux/notifier.h> -#endif - -#include <asm/atomic.h> -#ifndef XEN -#include <asm/cpu.h> -#endif -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/system.h> -#include <asm/bitops.h> -#include <asm/uaccess.h> -#include <asm/pgalloc.h> -#ifndef XEN -#include <asm/tlbflush.h> -#endif -#include <asm/delay.h> -#include <asm/irq.h> - -#ifdef XEN -#include <xen/event.h> -#define _irq_desc irq_desc -#define irq_descp(irq) &irq_desc[irq] -#define apicid_to_phys_cpu_present(x) 1 -#endif - - -/* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the appropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. - */ - -/* - * Controller mappings for all interrupt sources: - */ -irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { - [0 ... NR_IRQS-1] = { - .status = IRQ_DISABLED, - .handler = &no_irq_type, - .lock = SPIN_LOCK_UNLOCKED - } -}; - -/* - * This is updated when the user sets irq affinity via /proc - */ -cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; - -#ifdef CONFIG_IA64_GENERIC -irq_desc_t * __ia64_irq_desc (unsigned int irq) -{ - return _irq_desc + irq; -} - -ia64_vector __ia64_irq_to_vector (unsigned int irq) -{ - return (ia64_vector) irq; -} - -unsigned int __ia64_local_vector_to_irq (ia64_vector vec) -{ - return (unsigned int) vec; -} -#endif - -static void register_irq_proc (unsigned int irq); - -/* - * Special irq handlers. - */ - -#ifdef XEN -void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } -#else -irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ return IRQ_NONE; } -#endif - -/* - * Generic no controller code - */ - -static void enable_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } -static void disable_none(unsigned int irq) { } -static void ack_none(unsigned int irq) -{ -/* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themselves, it doesn't deserve - * a generic callback i think. - */ -#ifdef CONFIG_X86 - printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); -#ifdef CONFIG_X86_LOCAL_APIC - /* - * Currently unexpected vectors happen only on SMP and APIC. - * We _must_ ack these because every local APIC has only N - * irq slots per priority level, and a 'hanging, unacked' IRQ - * holds up an irq slot - in excessive cases (when multiple - * unexpected vectors occur) that might lock up the APIC - * completely. - */ - ack_APIC_irq(); -#endif -#endif -#ifdef CONFIG_IA64 - printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); -#endif -} - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define shutdown_none disable_none -#define end_none enable_none - -struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none -}; - -atomic_t irq_err_count; -#ifdef CONFIG_X86_IO_APIC -#ifdef APIC_MISMATCH_DEBUG -atomic_t irq_mis_count; -#endif -#endif - -/* - * Generic, controller-independent functions: - */ - -#ifndef XEN -int show_interrupts(struct seq_file *p, void *v) -{ - int j, i = *(loff_t *) v; - struct irqaction * action; - irq_desc_t *idesc; - unsigned long flags; - - if (i == 0) { - seq_puts(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); - } - - if (i < NR_IRQS) { - idesc = irq_descp(i); - spin_lock_irqsave(&idesc->lock, flags); - action = idesc->action; - if (!action) - goto skip; - seq_printf(p, "%3d: ",i); -#ifndef CONFIG_SMP - seq_printf(p, "%10u ", kstat_irqs(i)); -#else - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif - seq_printf(p, " %14s", idesc->handler->typename); - seq_printf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - seq_printf(p, ", %s", action->name); - - seq_putc(p, '\n'); -skip: - spin_unlock_irqrestore(&idesc->lock, flags); - } else if (i == NR_IRQS) { - seq_puts(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); - seq_putc(p, '\n'); -#ifdef CONFIG_X86_LOCAL_APIC - seq_puts(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); - seq_putc(p, '\n'); -#endif - seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); -#ifdef CONFIG_X86_IO_APIC -#ifdef APIC_MISMATCH_DEBUG - seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); -#endif -#endif - } - return 0; -} -#endif - -#ifdef CONFIG_SMP -inline void synchronize_irq(unsigned int irq) -{ -#ifndef XEN - struct irq_desc *desc = irq_desc + irq; - - while (desc->status & IRQ_INPROGRESS) - cpu_relax(); -#endif -} -EXPORT_SYMBOL(synchronize_irq); -#endif - -/* - * This should really return information about whether - * we should do bottom half handling etc. Right now we - * end up _always_ checking the bottom half, which is a - * waste of time and is not what some drivers would - * prefer. - */ -int handle_IRQ_event(unsigned int irq, - struct pt_regs *regs, struct irqaction *action) -{ - int status = 1; /* Force the "do bottom halves" bit */ - int retval = 0; - -#ifndef XEN - if (!(action->flags & SA_INTERRUPT)) -#endif - local_irq_enable(); - -#ifdef XEN - action->handler(irq, action->dev_id, regs); -#else - do { - status |= action->flags; - retval |= action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); -#endif - local_irq_disable(); - return retval; -} - -#ifndef XEN -static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - struct irqaction *action; - - if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { - printk(KERN_ERR "irq event %d: bogus return value %x\n", - irq, action_ret); - } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); - } - dump_stack(); - printk(KERN_ERR "handlers:\n"); - action = desc->action; - do { - printk(KERN_ERR "[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; - } while (action); -} - -static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - static int count = 100; - - if (count) { - count--; - __report_bad_irq(irq, desc, action_ret); - } -} -#endif - -static int noirqdebug; - -static int __init noirqdebug_setup(char *str) -{ - noirqdebug = 1; - printk("IRQ lockup detection disabled\n"); - return 1; -} - -__setup("noirqdebug", noirqdebug_setup); - -/* - * If 99,900 of the previous 100,000 interrupts have not been handled then - * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to - * turn the IRQ off. - * - * (The other 100-of-100,000 interrupts may have been a correctly-functioning - * device sharing an IRQ with the failing one) - * - * Called under desc->lock - */ -#ifndef XEN -static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - if (action_ret != IRQ_HANDLED) { - desc->irqs_unhandled++; - if (action_ret != IRQ_NONE) - report_bad_irq(irq, desc, action_ret); - } - - desc->irq_count++; - if (desc->irq_count < 100000) - return; - - desc->irq_count = 0; - if (desc->irqs_unhandled > 99900) { - /* - * The interrupt is stuck - */ - __report_bad_irq(irq, desc, action_ret); - /* - * Now kill the IRQ - */ - printk(KERN_EMERG "Disabling IRQ #%d\n", irq); - desc->status |= IRQ_DISABLED; - desc->handler->disable(irq); - } - desc->irqs_unhandled = 0; -} -#endif - -/* - * Generic enable/disable code: this just calls - * down into the PIC-specific version for the actual - * hardware disable after having gotten the irq - * controller lock. - */ - -/** - * disable_irq_nosync - disable an irq without waiting - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Disables and Enables are - * nested. - * Unlike disable_irq(), this function does not ensure existing - * instances of the IRQ handler have completed before returning. - * - * This function may be called from IRQ context. - */ - -inline void disable_irq_nosync(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - - spin_lock_irqsave(&desc->lock, flags); - if (!desc->depth++) { - desc->status |= IRQ_DISABLED; - desc->handler->disable(irq); - } - spin_unlock_irqrestore(&desc->lock, flags); -} -EXPORT_SYMBOL(disable_irq_nosync); - -/** - * disable_irq - disable an irq and wait for completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and Disables are - * nested. - * This function waits for any pending IRQ handlers for this interrupt - * to complete before returning. If you use this function while - * holding a resource the IRQ handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ - -void disable_irq(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - - disable_irq_nosync(irq); - if (desc->action) - synchronize_irq(irq); -} -EXPORT_SYMBOL(disable_irq); - -/** - * enable_irq - enable handling of an irq - * @irq: Interrupt to enable - * - * Undoes the effect of one call to disable_irq(). If this - * matches the last disable, processing of interrupts on this - * IRQ line is re-enabled. - * - * This function may be called from IRQ context. - */ - -void enable_irq(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - - spin_lock_irqsave(&desc->lock, flags); - switch (desc->depth) { - case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; - desc->status = status; -#ifndef XEN - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; - hw_resend_irq(desc->handler,irq); - } -#endif - desc->handler->enable(irq); - /* fall-through */ - } - default: - desc->depth--; - break; - case 0: - printk(KERN_ERR "enable_irq(%u) unbalanced from %p\n", - irq, (void *) __builtin_return_address(0)); - } - spin_unlock_irqrestore(&desc->lock, flags); -} -EXPORT_SYMBOL(enable_irq); - -/* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - */ -fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) -{ - irq_desc_t *desc = irq_desc + irq; - struct irqaction * action; - unsigned int status; - -#ifndef XEN - kstat_this_cpu.irqs[irq]++; -#endif - if (desc->status & IRQ_PER_CPU) { - irqreturn_t action_ret; - - /* - * No locking required for CPU-local interrupts: - */ - desc->handler->ack(irq); - action_ret = handle_IRQ_event(irq, regs, desc->action); -#ifndef XEN - if (!noirqdebug) - note_interrupt(irq, desc, action_ret); -#endif - desc->handler->end(irq); - return 1; - } - - spin_lock(&desc->lock); - desc->handler->ack(irq); - /* - * REPLAY is when Linux resends an IRQ that was dropped earlier - * WAITING is used by probe to mark irqs that are being tested - */ -#ifdef XEN - status = desc->status & ~IRQ_REPLAY; -#else - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); -#endif - status |= IRQ_PENDING; /* we _want_ to handle it */ - - /* - * If the IRQ is disabled for whatever reason, we cannot - * use the action we have. - */ - action = NULL; - if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { - action = desc->action; - status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ - } - desc->status = status; - - /* - * If there is no IRQ handler or it was disabled, exit early. - * Since we set PENDING, if another processor is handling - * a different instance of this same irq, the other processor - * will take care of it. - */ - if (unlikely(!action)) - goto out; - - /* - * Edge triggered interrupts need to remember - * pending events. - * This applies to any hw interrupts that allow a second - * instance of the same irq to arrive while we are in do_IRQ - * or in the handler. But the code here only handles the _second_ - * instance of the irq, not the third or fourth. So it is mostly - * useful for irq hardware that does not mask cleanly in an - * SMP environment. - */ - for (;;) { - irqreturn_t action_ret; - - spin_unlock(&desc->lock); - - action_ret = handle_IRQ_event(irq, regs, action); - - spin_lock(&desc->lock); -#ifndef XEN - if (!noirqdebug) - note_interrupt(irq, desc, action_ret); -#endif - if (likely(!(desc->status & IRQ_PENDING))) - break; - desc->status &= ~IRQ_PENDING; - } - desc->status &= ~IRQ_INPROGRESS; - -out: - /* - * The ->end() handler has to deal with interrupts which got - * disabled while the handler was running. - */ - desc->handler->end(irq); - spin_unlock(&desc->lock); - - return 1; -} - -/** - * request_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. From the point this - * call is made your handler function may be invoked. Since - * your handler function must clear any interrupt the board - * raises, you must take care both to initialise your hardware - * and to set up the interrupt handler in the right order. - * - * Dev_id must be globally unique. Normally the address of the - * device data structure is used as the cookie. Since the handler - * receives this value it makes sense to use it. - * - * If your interrupt is shared you must pass a non NULL dev_id - * as this is required when freeing the interrupt. - * - * Flags: - * - * SA_SHIRQ Interrupt is shared - * - * SA_INTERRUPT Disable local interrupts while processing - * - * SA_SAMPLE_RANDOM The interrupt can be used for entropy - * - */ - -int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - int retval; - struct irqaction * action; - -#if 1 - /* - * Sanity-check: shared interrupts should REALLY pass in - * a real dev-ID, otherwise we'll have trouble later trying - * to figure out which interrupt is which (messes up the - * interrupt freeing logic etc). - */ - if (irqflags & SA_SHIRQ) { - if (!dev_id) - printk(KERN_ERR "Bad boy: %s called us without a dev_id!\n", devname); - } -#endif - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = xmalloc(struct irqaction); - if (!action) - return -ENOMEM; - - action->handler = handler; -#ifndef XEN - action->flags = irqflags; - action->mask = 0; -#endif - action->name = devname; -#ifndef XEN - action->next = NULL; -#endif - action->dev_id = dev_id; - - retval = setup_irq(irq, action); - if (retval) - xfree(action); - return retval; -} - -EXPORT_SYMBOL(request_irq); - -/** - * free_irq - free an interrupt - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove an interrupt handler. The handler is removed and if the - * interrupt line is no longer in use by any driver it is disabled. - * On a shared IRQ the caller must ensure the interrupt is disabled - * on the card it drives before calling this function. The function - * does not return until any executing interrupts for this IRQ - * have completed. - * - * This function must not be called from interrupt context. - */ - -#ifdef XEN -void free_irq(unsigned int irq) -#else -void free_irq(unsigned int irq, void *dev_id) -#endif -{ - irq_desc_t *desc; - struct irqaction **p; - unsigned long flags; - - if (irq >= NR_IRQS) - return; - - desc = irq_descp(irq); - spin_lock_irqsave(&desc->lock,flags); -#ifdef XEN - if (desc->action) { - struct irqaction * action = desc->action; - desc->action = NULL; -#else - p = &desc->action; - for (;;) { - struct irqaction * action = *p; - if (action) { - struct irqaction **pp = p; - p = &action->next; - if (action->dev_id != dev_id) - continue; - - /* Found it - now remove it from the list of entries */ - *pp = action->next; - if (!desc->action) { -#endif - desc->status |= IRQ_DISABLED; - desc->handler->shutdown(irq); -#ifndef XEN - } -#endif - spin_unlock_irqrestore(&desc->lock,flags); - - /* Wait to make sure it's not being used on another CPU */ - synchronize_irq(irq); - xfree(action); - return; - } - printk(KERN_ERR "Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&desc->lock,flags); -#ifndef XEN - return; - } -#endif -} - -EXPORT_SYMBOL(free_irq); - -/* - * IRQ autodetection code.. - * - * This depends on the fact that any interrupt that - * comes in on to an unassigned handler will get stuck - * with "IRQ_WAITING" cleared and the interrupt - * disabled. - */ - -static DECLARE_MUTEX(probe_sem); - -/** - * probe_irq_on - begin an interrupt autodetect - * - * Commence probing for an interrupt. The interrupts are scanned - * and a mask of potential interrupt lines is returned. - * - */ - -#ifndef XEN -unsigned long probe_irq_on(void) -{ - unsigned int i; - irq_desc_t *desc; - unsigned long val; - unsigned long delay; - - down(&probe_sem); - /* - * something may have generated an irq long ago and we want to - * flush such a longstanding irq before considering it as spurious. - */ - for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_descp(i); - - spin_lock_irq(&desc->lock); - if (!desc->action) - desc->handler->startup(i); - spin_unlock_irq(&desc->lock); - } - - /* Wait for longstanding interrupts to trigger. */ - for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ barrier(); - - /* - * enable any unassigned irqs - * (we must startup again here because if a longstanding irq - * happened in the previous stage, it may have masked itself) - */ - for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_descp(i); - - spin_lock_irq(&desc->lock); - if (!desc->action) { - desc->status |= IRQ_AUTODETECT | IRQ_WAITING; - if (desc->handler->startup(i)) - desc->status |= IRQ_PENDING; - } - spin_unlock_irq(&desc->lock); - } - - /* - * Wait for spurious interrupts to trigger - */ - for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ barrier(); - - /* - * Now filter out any obviously spurious interrupts - */ - val = 0; - for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - /* It triggered already - consider it spurious. */ - if (!(status & IRQ_WAITING)) { - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } else - if (i < 32) - val |= 1 << i; - } - spin_unlock_irq(&desc->lock); - } - - return val; -} - -EXPORT_SYMBOL(probe_irq_on); - -/** - * probe_irq_mask - scan a bitmap of interrupt lines - * @val: mask of interrupts to consider - * - * Scan the ISA bus interrupt lines and return a bitmap of - * active interrupts. The interrupt probe logic state is then - * returned to its previous value. - * - * Note: we need to scan all the irq's even though we will - * only return ISA irq numbers - just so that we reset them - * all to a known state. - */ -unsigned int probe_irq_mask(unsigned long val) -{ - int i; - unsigned int mask; - - mask = 0; - for (i = 0; i < 16; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - if (!(status & IRQ_WAITING)) - mask |= 1 << i; - - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } - spin_unlock_irq(&desc->lock); - } - up(&probe_sem); - - return mask & val; -} -EXPORT_SYMBOL(probe_irq_mask); - -/** - * probe_irq_off - end an interrupt autodetect - * @val: mask of potential interrupts (unused) - * - * Scans the unused interrupt lines and returns the line which - * appears to have triggered the interrupt. If no interrupt was - * found then zero is returned. If more than one interrupt is - * found then minus the first candidate is returned to indicate - * their is doubt. - * - * The interrupt probe logic state is returned to its previous - * value. - * - * BUGS: When used in a module (which arguably shouldn't happen) - * nothing prevents two IRQ probe callers from overlapping. The - * results of this are non-optimal. - */ - -int probe_irq_off(unsigned long val) -{ - int i, irq_found, nr_irqs; - - nr_irqs = 0; - irq_found = 0; - for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - if (!(status & IRQ_WAITING)) { - if (!nr_irqs) - irq_found = i; - nr_irqs++; - } - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } - spin_unlock_irq(&desc->lock); - } - up(&probe_sem); - - if (nr_irqs > 1) - irq_found = -irq_found; - return irq_found; -} - -EXPORT_SYMBOL(probe_irq_off); -#endif - -int setup_irq(unsigned int irq, struct irqaction * new) -{ - int shared = 0; - unsigned long flags; - struct irqaction *old, **p; - irq_desc_t *desc = irq_descp(irq); - -#ifndef XEN - if (desc->handler == &no_irq_type) - return -ENOSYS; - /* - * Some drivers like serial.c use request_irq() heavily, - * so we have to be careful not to interfere with a - * running system. - */ - if (new->flags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(irq); - } - - if (new->flags & SA_PERCPU_IRQ) { - desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_ia64_lsapic; - } -#endif - - /* - * The following block of code has to be executed atomically - */ - spin_lock_irqsave(&desc->lock,flags); - p = &desc->action; - if ((old = *p) != NULL) { -#ifdef XEN - if (1) { - /* Can't share interrupts unless both agree to */ -#else - if (!(old->flags & new->flags & SA_SHIRQ)) { -#endif - spin_unlock_irqrestore(&desc->lock,flags); - return -EBUSY; - } - -#ifndef XEN - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; -#endif - } - - *p = new; - -#ifndef XEN - if (!shared) { -#else - { -#endif - desc->depth = 0; -#ifdef XEN - desc->status &= ~(IRQ_DISABLED | IRQ_INPROGRESS); -#else - desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); -#endif - desc->handler->startup(irq); - } - spin_unlock_irqrestore(&desc->lock,flags); - -#ifndef XEN - register_irq_proc(irq); -#endif - return 0; -} - -#ifndef XEN - -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; - -#ifdef CONFIG_SMP - -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; - -static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; - -static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; - -void set_irq_affinity_info (unsigned int irq, int hwid, int redir) -{ - cpumask_t mask = CPU_MASK_NONE; - - cpu_set(cpu_logical_id(hwid), mask); - - if (irq < NR_IRQS) { - irq_affinity[irq] = mask; - irq_redir[irq] = (char) (redir & 0xff); - } -} - -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = sprintf(page, "%s", irq_redir[(long)data] ? "r " : ""); - - len += cpumask_scnprintf(page+len, count, irq_affinity[(long)data]); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int irq_affinity_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - unsigned int irq = (unsigned long) data; - int full_count = count, err; - cpumask_t new_value, tmp; -# define R_PREFIX_LEN 16 - char rbuf[R_PREFIX_LEN]; - int rlen; - int prelen; - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - - if (!desc->handler->set_affinity) - return -EIO; - - /* - * If string being written starts with a prefix of 'r' or 'R' - * and some limited number of spaces, set IA64_IRQ_REDIRECTED. - * If more than (R_PREFIX_LEN - 2) spaces are passed, they won't - * all be trimmed as part of prelen, the untrimmed spaces will - * cause the hex parsing to fail, and this write() syscall will - * fail with EINVAL. - */ - - if (!count) - return -EINVAL; - rlen = min(sizeof(rbuf)-1, count); - if (copy_from_user(rbuf, buffer, rlen)) - return -EFAULT; - rbuf[rlen] = 0; - prelen = 0; - if (tolower(*rbuf) == 'r') { - prelen = strspn(rbuf, "Rr "); - irq |= IA64_IRQ_REDIRECTED; - } - - err = cpumask_parse(buffer+prelen, count-prelen, new_value); - if (err) - return err; - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) - return -EINVAL; - - spin_lock_irqsave(&desc->lock, flags); - pending_irq_cpumask[irq] = new_value; - spin_unlock_irqrestore(&desc->lock, flags); - - return full_count; -} - -void move_irq(int irq) -{ - /* note - we hold desc->lock */ - cpumask_t tmp; - irq_desc_t *desc = irq_descp(irq); - - if (!cpus_empty(pending_irq_cpumask[irq])) { - cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); - if (unlikely(!cpus_empty(tmp))) { - desc->handler->set_affinity(irq, pending_irq_cpumask[irq]); - } - cpus_clear(pending_irq_cpumask[irq]); - } -} - - -#endif /* CONFIG_SMP */ -#endif - -#ifdef CONFIG_HOTPLUG_CPU -unsigned int vectors_in_migration[NR_IRQS]; - -/* - * Since cpu_online_map is already updated, we just need to check for - * affinity that has zeros - */ -static void migrate_irqs(void) -{ - cpumask_t mask; - irq_desc_t *desc; - int irq, new_cpu; - - for (irq=0; irq < NR_IRQS; irq++) { - desc = irq_descp(irq); - - /* - * No handling for now. - * TBD: Implement a disable function so we can now - * tell CPU not to respond to these local intr sources. - * such as ITV,CPEI,MCA etc. - */ - if (desc->status == IRQ_PER_CPU) - continue; - - cpus_and(mask, irq_affinity[irq], cpu_online_map); - if (any_online_cpu(mask) == NR_CPUS) { - /* - * Save it for phase 2 processing - */ - vectors_in_migration[irq] = irq; - - new_cpu = any_online_cpu(cpu_online_map); - mask = cpumask_of_cpu(new_cpu); - - /* - * Al three are essential, currently WARN_ON.. maybe panic? - */ - if (desc->handler && desc->handler->disable && - desc->handler->enable && desc->handler->set_affinity) { - desc->handler->disable(irq); - desc->handler->set_affinity(irq, mask); - desc->handler->enable(irq); - } else { - WARN_ON((!(desc->handler) || !(desc->handler->disable) || - !(desc->handler->enable) || - !(desc->handler->set_affinity))); - } - } - } -} - -void fixup_irqs(void) -{ - unsigned int irq; - extern void ia64_process_pending_intr(void); - - ia64_set_itv(1<<16); - /* - * Phase 1: Locate irq's bound to this cpu and - * relocate them for cpu removal. - */ - migrate_irqs(); - - /* - * Phase 2: Perform interrupt processing for all entries reported in - * local APIC. - */ - ia64_process_pending_intr(); - - /* - * Phase 3: Now handle any interrupts not captured in local APIC. - * This is to account for cases that device interrupted during the time the - * rte was being disabled and re-programmed. - */ - for (irq=0; irq < NR_IRQS; irq++) { - if (vectors_in_migration[irq]) { - vectors_in_migration[irq]=0; - do_IRQ(irq, NULL); - } - } - - /* - * Now let processor die. We do irq disable and max_xtp() to - * ensure there is no more interrupts routed to this processor. - * But the local timer interrupt can have 1 pending which we - * take care in timer_interrupt(). - */ - max_xtp(); - local_irq_disable(); -} -#endif - -#ifndef XEN -static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - cpumask_t *mask = (cpumask_t *)data; - unsigned long full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - if (err) - return err; - - *mask = new_value; - return full_count; -} - -#define MAX_NAMELEN 10 - -static void register_irq_proc (unsigned int irq) -{ - char name [MAX_NAMELEN]; - - if (!root_irq_dir || (irq_descp(irq)->handler == &no_irq_type) || irq_dir[irq]) - return; - - memset(name, 0, MAX_NAMELEN); - sprintf(name, "%d", irq); - - /* create /proc/irq/1234 */ - irq_dir[irq] = proc_mkdir(name, root_irq_dir); - -#ifdef CONFIG_SMP - { - struct proc_dir_entry *entry; - - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - if (entry) { - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; - } - - smp_affinity_entry[irq] = entry; - } -#endif -} - -cpumask_t prof_cpu_mask = CPU_MASK_ALL; - -void init_irq_proc (void) -{ - struct proc_dir_entry *entry; - int i; - - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); - - /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - - if (!entry) - return; - - entry->nlink = 1; - entry->data = (void *)&prof_cpu_mask; - entry->read_proc = prof_cpu_mask_read_proc; - entry->write_proc = prof_cpu_mask_write_proc; - - /* - * Create entries for all existing IRQs. - */ - for (i = 0; i < NR_IRQS; i++) { - if (irq_descp(i)->handler == &no_irq_type) - continue; - register_irq_proc(i); - } -} -#endif - - -#ifdef XEN -/* - * HANDLING OF GUEST-BOUND PHYSICAL IRQS - */ - -#define IRQ_MAX_GUESTS 7 -typedef struct { - u8 nr_guests; - u8 in_flight; - u8 shareable; - struct domain *guest[IRQ_MAX_GUESTS]; -} irq_guest_action_t; - -static void __do_IRQ_guest(int irq) -{ - irq_desc_t *desc = &irq_desc[irq]; - irq_guest_action_t *action = (irq_guest_action_t *)desc->action; - struct domain *d; - int i; - - for ( i = 0; i < action->nr_guests; i++ ) - { - d = action->guest[i]; - if ( !test_and_set_bit(irq, &d->pirq_mask) ) - action->in_flight++; - send_guest_pirq(d, irq); - } -} - -int pirq_guest_unmask(struct domain *d) -{ - irq_desc_t *desc; - int i, j, pirq; - u32 m; - shared_info_t *s = d->shared_info; - - for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ ) - { - m = d->pirq_mask[i]; - while ( (j = ffs(m)) != 0 ) - { - m &= ~(1 << --j); - pirq = (i << 5) + j; - desc = &irq_desc[pirq]; - spin_lock_irq(&desc->lock); - if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) && - test_and_clear_bit(pirq, &d->pirq_mask) && - (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) - desc->handler->end(pirq); - spin_unlock_irq(&desc->lock); - } - } - - return 0; -} - -int pirq_guest_bind(struct vcpu *d, int irq, int will_share) -{ - irq_desc_t *desc = &irq_desc[irq]; - irq_guest_action_t *action; - unsigned long flags; - int rc = 0; - - if ( !IS_CAPABLE_PHYSDEV(d->domain) ) - return -EPERM; - - spin_lock_irqsave(&desc->lock, flags); - - action = (irq_guest_action_t *)desc->action; - - if ( !(desc->status & IRQ_GUEST) ) - { - if ( desc->action != NULL ) - { - DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n", - irq, desc->action->name); - rc = -EBUSY; - goto out; - } - - action = xmalloc(irq_guest_action_t); - if ( (desc->action = (struct irqaction *)action) == NULL ) - { - DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq); - rc = -ENOMEM; - goto out; - } - - action->nr_guests = 0; - action->in_flight = 0; - action->shareable = will_share; - - desc->depth = 0; - desc->status |= IRQ_GUEST; - desc->status &= ~IRQ_DISABLED; - desc->handler->startup(irq); - - /* Attempt to bind the interrupt target to the correct CPU. */ -#if 0 /* FIXME CONFIG_SMP ??? */ - if ( desc->handler->set_affinity != NULL ) - desc->handler->set_affinity( - irq, apicid_to_phys_cpu_present(d->processor)); -#endif - } - else if ( !will_share || !action->shareable ) - { - DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n", - irq); - rc = -EBUSY; - goto out; - } - - if ( action->nr_guests == IRQ_MAX_GUESTS ) - { - DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq); - rc = -EBUSY; - goto out; - } - - action->guest[action->nr_guests++] = d; - - out: - spin_unlock_irqrestore(&desc->lock, flags); - return rc; -} - -int pirq_guest_unbind(struct domain *d, int irq) -{ - irq_desc_t *desc = &irq_desc[irq]; - irq_guest_action_t *action; - unsigned long flags; - int i; - - spin_lock_irqsave(&desc->lock, flags); - - action = (irq_guest_action_t *)desc->action; - - if ( test_and_clear_bit(irq, &d->pirq_mask) && - (--action->in_flight == 0) ) - desc->handler->end(irq); - - if ( action->nr_guests == 1 ) - { - desc->action = NULL; - xfree(action); - desc->depth = 1; - desc->status |= IRQ_DISABLED; - desc->status &= ~IRQ_GUEST; - desc->handler->shutdown(irq); - } - else - { - i = 0; - while ( action->guest[i] != d ) - i++; - memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1); - action->nr_guests--; - } - - spin_unlock_irqrestore(&desc->lock, flags); - return 0; -} - -#endif - -#ifdef XEN -#ifdef IA64 -// this is a temporary hack until real console input is implemented -irqreturn_t guest_forward_keyboard_input(int irq, void *nada, struct pt_regs *regs) -{ - domain_pend_keyboard_interrupt(irq); -} - -void serial_input_init(void) -{ - int retval; - int irq = 0x30; // FIXME - - retval = request_irq(irq,guest_forward_keyboard_input,SA_INTERRUPT,"siminput",NULL); - if (retval) { - printk("serial_input_init: broken request_irq call\n"); - while(1); - } -} -#endif -#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/ivt.S --- a/xen/arch/ia64/ivt.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1975 +0,0 @@ - -#ifdef XEN -//#define CONFIG_DISABLE_VHPT // FIXME: change when VHPT is enabled?? -// these are all hacked out for now as the entire IVT -// will eventually be replaced... just want to use it -// for startup code to handle TLB misses -//#define ia64_leave_kernel 0 -//#define ia64_ret_from_syscall 0 -//#define ia64_handle_irq 0 -//#define ia64_fault 0 -#define ia64_illegal_op_fault 0 -#define ia64_prepare_handle_unaligned 0 -#define ia64_bad_break 0 -#define ia64_trace_syscall 0 -#define sys_call_table 0 -#define sys_ni_syscall 0 -#include <asm/vhpt.h> -#endif -/* - * arch/ia64/kernel/ivt.S - * - * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co - * Stephane Eranian <eranian@xxxxxxxxxx> - * David Mosberger <davidm@xxxxxxxxxx> - * Copyright (C) 2000, 2002-2003 Intel Co - * Asit Mallick <asit.k.mallick@xxxxxxxxx> - * Suresh Siddha <suresh.b.siddha@xxxxxxxxx> - * Kenneth Chen <kenneth.w.chen@xxxxxxxxx> - * Fenghua Yu <fenghua.yu@xxxxxxxxx> - * - * 00/08/23 Asit Mallick <asit.k.mallick@xxxxxxxxx> TLB handling for SMP - * 00/12/20 David Mosberger-Tang <davidm@xxxxxxxxxx> DTLB/ITLB handler now uses virtual PT. - */ -/* - * This file defines the interruption vector table used by the CPU. - * It does not include one entry per possible cause of interruption. - * - * The first 20 entries of the table contain 64 bundles each while the - * remaining 48 entries contain only 16 bundles each. - * - * The 64 bundles are used to allow inlining the whole handler for critical - * interruptions like TLB misses. - * - * For each entry, the comment is as follows: - * - * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) - * entry offset ----/ / / / / - * entry number ---------/ / / / - * size of the entry -------------/ / / - * vector name -------------------------------------/ / - * interruptions triggering this vector ----------------------/ - * - * The table is 32KB in size and must be aligned on 32KB boundary. - * (The CPU ignores the 15 lower bits of the address) - * - * Table is based upon EAS2.6 (Oct 1999) - */ - -#include <linux/config.h> - -#include <asm/asmmacro.h> -#include <asm/break.h> -#include <asm/ia32.h> -#include <asm/kregs.h> -#include <asm/offsets.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/system.h> -#include <asm/thread_info.h> -#include <asm/unistd.h> -#include <asm/errno.h> - -#if 1 -# define PSR_DEFAULT_BITS psr.ac -#else -# define PSR_DEFAULT_BITS 0 -#endif - -#if 0 - /* - * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't - * needed for something else before enabling this... - */ -# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 -#else -# define DBG_FAULT(i) -#endif - -#define MINSTATE_VIRT /* needed by minstate.h */ -#include "minstate.h" - -#define FAULT(n) \ - mov r31=pr; \ - mov r19=n;; /* prepare to save predicates */ \ - br.sptk.many dispatch_to_fault_handler - -#ifdef XEN -#define REFLECT(n) \ - mov r31=pr; \ - mov r19=n;; /* prepare to save predicates */ \ - br.sptk.many dispatch_reflection -#endif - - .section .text.ivt,"ax" - - .align 32768 // align on 32KB boundary - .global ia64_ivt -ia64_ivt: -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) -ENTRY(vhpt_miss) - DBG_FAULT(0) - /* - * The VHPT vector is invoked when the TLB entry for the virtual page table - * is missing. This happens only as a result of a previous - * (the "original") TLB miss, which may either be caused by an instruction - * fetch or a data access (or non-access). - * - * What we do here is normal TLB miss handing for the _original_ miss, followed - * by inserting the TLB entry for the virtual page table page that the VHPT - * walker was attempting to access. The latter gets inserted as long - * as both L1 and L2 have valid mappings for the faulting address. - * The TLB entry for the original miss gets inserted only if - * the L3 entry indicates that the page is present. - * - * do_page_fault gets invoked in the following cases: - * - the faulting virtual address uses unimplemented address bits - * - the faulting virtual address has no L1, L2, or L3 mapping - */ - mov r16=cr.ifa // get address that caused the TLB miss -#ifdef CONFIG_HUGETLB_PAGE - movl r18=PAGE_SHIFT - mov r25=cr.itir -#endif - ;; - rsm psr.dt // use physical addressing for data - mov r31=pr // save the predicate registers -#ifdef XEN - movl r19=THIS_CPU(cpu_kr)+IA64_KR_PT_BASE_OFFSET;; -#else - mov r19=IA64_KR(PT_BASE) // get page table base address -#endif - shl r21=r16,3 // shift bit 60 into sign bit - shr.u r17=r16,61 // get the region number into r17 - ;; - shr r22=r21,3 -#ifdef CONFIG_HUGETLB_PAGE - extr.u r26=r25,2,6 - ;; - cmp.ne p8,p0=r18,r26 - sub r27=r26,r18 - ;; -(p8) dep r25=r18,r25,2,6 -(p8) shr r22=r22,r27 -#endif - ;; - cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? - shr.u r18=r22,PGDIR_SHIFT // get bits 33-63 of the faulting address - ;; -(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place - - srlz.d - LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir - - .pred.rel "mutex", p6, p7 -(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT -(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 - ;; -(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 -(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) - cmp.eq p7,p6=0,r21 // unused address bits all zeroes? - shr.u r18=r22,PMD_SHIFT // shift L2 index into position - ;; - ld8 r17=[r17] // fetch the L1 entry (may be 0) - ;; -(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? - dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry - ;; -(p7) ld8 r20=[r17] // fetch the L2 entry (may be 0) - shr.u r19=r22,PAGE_SHIFT // shift L3 index into position - ;; -(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L2 entry NULL? - dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L3 page table entry - ;; -(p7) ld8 r18=[r21] // read the L3 PTE - mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss - ;; -(p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared? - mov r22=cr.iha // get the VHPT address that caused the TLB miss - ;; // avoid RAW on p7 -(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? - dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address - ;; -(p10) itc.i r18 // insert the instruction TLB entry -(p11) itc.d r18 // insert the data TLB entry -(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) - mov cr.ifa=r22 - -#ifdef CONFIG_HUGETLB_PAGE -(p8) mov cr.itir=r25 // change to default page-size for VHPT -#endif - - /* - * Now compute and insert the TLB entry for the virtual page table. We never - * execute in a page table page so there is no need to set the exception deferral - * bit. - */ - adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 - ;; -(p7) itc.d r24 - ;; -#ifdef CONFIG_SMP - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - - /* - * Re-check L2 and L3 pagetable. If they changed, we may have received a ptc.g - * between reading the pagetable and the "itc". If so, flush the entry we - * inserted and retry. - */ - ld8 r25=[r21] // read L3 PTE again - ld8 r26=[r17] // read L2 entry again - ;; - cmp.ne p6,p7=r26,r20 // did L2 entry change - mov r27=PAGE_SHIFT<<2 - ;; -(p6) ptc.l r22,r27 // purge PTE page translation -(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did L3 PTE change - ;; -(p6) ptc.l r16,r27 // purge translation -#endif - - mov pr=r31,-1 // restore predicate registers - rfi -END(vhpt_miss) - - .org ia64_ivt+0x400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0400 Entry 1 (size 64 bundles) ITLB (21) -ENTRY(itlb_miss) - DBG_FAULT(1) -#ifdef XEN - VHPT_CCHAIN_LOOKUP(itlb_miss,i) -#ifdef VHPT_GLOBAL - br.cond.sptk page_fault - ;; -#endif -#endif - /* - * The ITLB handler accesses the L3 PTE via the virtually mapped linear - * page table. If a nested TLB miss occurs, we switch into physical - * mode, walk the page table, and then re-execute the L3 PTE read - * and go on normally after that. - */ - mov r16=cr.ifa // get virtual address - mov r29=b0 // save b0 - mov r31=pr // save predicates -.itlb_fault: - mov r17=cr.iha // get virtual address of L3 PTE - movl r30=1f // load nested fault continuation point - ;; -1: ld8 r18=[r17] // read L3 PTE - ;; - mov b0=r29 - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt page_fault - ;; - itc.i r18 - ;; -#ifdef CONFIG_SMP - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - - ld8 r19=[r17] // read L3 PTE again and see if same - mov r20=PAGE_SHIFT<<2 // setup page size for purge - ;; - cmp.ne p7,p0=r18,r19 - ;; -(p7) ptc.l r16,r20 -#endif - mov pr=r31,-1 - rfi -END(itlb_miss) - - .org ia64_ivt+0x0800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) -ENTRY(dtlb_miss) - DBG_FAULT(2) -#ifdef XEN - VHPT_CCHAIN_LOOKUP(dtlb_miss,d) -#ifdef VHPT_GLOBAL - br.cond.sptk page_fault - ;; -#endif -#endif - /* - * The DTLB handler accesses the L3 PTE via the virtually mapped linear - * page table. If a nested TLB miss occurs, we switch into physical - * mode, walk the page table, and then re-execute the L3 PTE read - * and go on normally after that. - */ - mov r16=cr.ifa // get virtual address - mov r29=b0 // save b0 - mov r31=pr // save predicates -dtlb_fault: - mov r17=cr.iha // get virtual address of L3 PTE - movl r30=1f // load nested fault continuation point - ;; -1: ld8 r18=[r17] // read L3 PTE - ;; - mov b0=r29 - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt page_fault - ;; - itc.d r18 - ;; -#ifdef CONFIG_SMP - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - - ld8 r19=[r17] // read L3 PTE again and see if same - mov r20=PAGE_SHIFT<<2 // setup page size for purge - ;; - cmp.ne p7,p0=r18,r19 - ;; -(p7) ptc.l r16,r20 -#endif - mov pr=r31,-1 - rfi -END(dtlb_miss) - - .org ia64_ivt+0x0c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) -ENTRY(alt_itlb_miss) - DBG_FAULT(3) -#ifdef XEN -//#ifdef VHPT_GLOBAL -// VHPT_CCHAIN_LOOKUP(alt_itlb_miss,i) -// br.cond.sptk page_fault -// ;; -//#endif -#endif -#ifdef XEN - mov r31=pr - mov r16=cr.ifa // get address that caused the TLB miss - ;; -late_alt_itlb_miss: - movl r17=PAGE_KERNEL - mov r21=cr.ipsr - movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) - ;; -#else - mov r16=cr.ifa // get address that caused the TLB miss - movl r17=PAGE_KERNEL - mov r21=cr.ipsr - movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) - mov r31=pr - ;; -#endif -#ifdef CONFIG_DISABLE_VHPT - shr.u r22=r16,61 // get the region number into r21 - ;; - cmp.gt p8,p0=6,r22 // user mode - ;; -(p8) thash r17=r16 - ;; -(p8) mov cr.iha=r17 -(p8) mov r29=b0 // save b0 -(p8) br.cond.dptk .itlb_fault -#endif - extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits -#ifdef XEN - shr.u r18=r16,55 // move address bit 59 to bit 4 - ;; - and r18=0x10,r18 // bit 4=address-bit(59) -#else - shr.u r18=r16,57 // move address bit 61 to bit 4 - ;; - andcm r18=0x10,r18 // bit 4=~address-bit(61) -#endif - cmp.ne p8,p0=r0,r23 // psr.cpl != 0? - or r19=r17,r19 // insert PTE control bits into r19 - ;; - or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 -(p8) br.cond.spnt page_fault - ;; - itc.i r19 // insert the TLB entry - mov pr=r31,-1 - rfi -END(alt_itlb_miss) - - .org ia64_ivt+0x1000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) -ENTRY(alt_dtlb_miss) - DBG_FAULT(4) -#ifdef XEN -//#ifdef VHPT_GLOBAL -// VHPT_CCHAIN_LOOKUP(alt_dtlb_miss,d) -// br.cond.sptk page_fault -// ;; -//#endif -#endif -#ifdef XEN - mov r31=pr - mov r16=cr.ifa // get address that caused the TLB miss - ;; -late_alt_dtlb_miss: - movl r17=PAGE_KERNEL - mov r20=cr.isr - movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) - mov r21=cr.ipsr - ;; -#else -#endif -#ifdef CONFIG_DISABLE_VHPT - shr.u r22=r16,61 // get the region number into r21 - ;; - cmp.gt p8,p0=6,r22 // access to region 0-5 - ;; -(p8) thash r17=r16 - ;; -(p8) mov cr.iha=r17 -(p8) mov r29=b0 // save b0 -(p8) br.cond.dptk dtlb_fault -#endif - extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl - and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field - tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? -#ifdef XEN - shr.u r18=r16,55 // move address bit 59 to bit 4 - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits - tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? - ;; - and r18=0x10,r18 // bit 4=address-bit(59) -#else - shr.u r18=r16,57 // move address bit 61 to bit 4 - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits - tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? - ;; - andcm r18=0x10,r18 // bit 4=~address-bit(61) -#endif - cmp.ne p8,p0=r0,r23 -(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field -(p8) br.cond.spnt page_fault -#ifdef XEN - ;; - // Test for Xen address, if not handle via page_fault - // note that 0xf000 (cached) and 0xe800 (uncached) addresses - // should be OK. - extr.u r22=r16,59,5;; - cmp.eq p8,p0=0x1e,r22 -(p8) br.cond.spnt 1f;; - cmp.ne p8,p0=0x1d,r22 -(p8) br.cond.sptk page_fault ;; -1: -#endif - - dep r21=-1,r21,IA64_PSR_ED_BIT,1 - or r19=r19,r17 // insert PTE control bits into r19 - ;; - or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 -(p6) mov cr.ipsr=r21 - ;; -(p7) itc.d r19 // insert the TLB entry - mov pr=r31,-1 - rfi -END(alt_dtlb_miss) - - .org ia64_ivt+0x1400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) -ENTRY(nested_dtlb_miss) - /* - * In the absence of kernel bugs, we get here when the virtually mapped linear - * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction - * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page - * table is missing, a nested TLB miss fault is triggered and control is - * transferred to this point. When this happens, we lookup the pte for the - * faulting address by walking the page table in physical mode and return to the - * continuation point passed in register r30 (or call page_fault if the address is - * not mapped). - * - * Input: r16: faulting address - * r29: saved b0 - * r30: continuation address - * r31: saved pr - * - * Output: r17: physical address of L3 PTE of faulting address - * r29: saved b0 - * r30: continuation address - * r31: saved pr - * - * Clobbered: b0, r18, r19, r21, psr.dt (cleared) - */ - rsm psr.dt // switch to using physical data addressing -#ifdef XEN - movl r19=THIS_CPU(cpu_kr)+IA64_KR_PT_BASE_OFFSET;; -#else - mov r19=IA64_KR(PT_BASE) // get the page table base address -#endif - shl r21=r16,3 // shift bit 60 into sign bit - ;; - shr.u r17=r16,61 // get the region number into r17 - ;; - cmp.eq p6,p7=5,r17 // is faulting address in region 5? - shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address - ;; -(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place - - srlz.d - LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir - - .pred.rel "mutex", p6, p7 -(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT -(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 - ;; -(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 -(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) - cmp.eq p7,p6=0,r21 // unused address bits all zeroes? - shr.u r18=r16,PMD_SHIFT // shift L2 index into position - ;; - ld8 r17=[r17] // fetch the L1 entry (may be 0) - ;; -(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? - dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry - ;; -(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) - shr.u r19=r16,PAGE_SHIFT // shift L3 index into position - ;; -(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? - dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry -(p6) br.cond.spnt page_fault - mov b0=r30 - br.sptk.many b0 // return to continuation point -END(nested_dtlb_miss) - - .org ia64_ivt+0x1800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) -ENTRY(ikey_miss) -#ifdef XEN - REFLECT(6) -#endif - DBG_FAULT(6) - FAULT(6) -END(ikey_miss) - - //----------------------------------------------------------------------------------- - // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address) -ENTRY(page_fault) - ssm psr.dt - ;; - srlz.i - ;; - SAVE_MIN_WITH_COVER -#ifdef XEN - alloc r15=ar.pfs,0,0,4,0 - mov out0=cr.ifa - mov out1=cr.isr - mov out3=cr.itir -#else - alloc r15=ar.pfs,0,0,3,0 - mov out0=cr.ifa - mov out1=cr.isr -#endif - adds r3=8,r2 // set up second base pointer - ;; - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collectin is on - ;; -(p15) ssm psr.i // restore psr.i - movl r14=ia64_leave_kernel - ;; - SAVE_REST - mov rp=r14 - ;; - adds out2=16,r12 // out2 = pointer to pt_regs - br.call.sptk.many b6=ia64_do_page_fault // ignore return address -END(page_fault) - - .org ia64_ivt+0x1c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) -ENTRY(dkey_miss) -#ifdef XEN - REFLECT(7) -#endif - DBG_FAULT(7) - FAULT(7) -END(dkey_miss) - - .org ia64_ivt+0x2000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) -ENTRY(dirty_bit) -#ifdef XEN - REFLECT(8) -#endif - DBG_FAULT(8) - /* - * What we do here is to simply turn on the dirty bit in the PTE. We need to - * update both the page-table and the TLB entry. To efficiently access the PTE, - * we address it through the virtual page table. Most likely, the TLB entry for - * the relevant virtual page table page is still present in the TLB so we can - * normally do this without additional TLB misses. In case the necessary virtual - * page table TLB entry isn't present, we take a nested TLB miss hit where we look - * up the physical address of the L3 PTE and then continue at label 1 below. - */ - mov r16=cr.ifa // get the address that caused the fault - movl r30=1f // load continuation point in case of nested fault - ;; - thash r17=r16 // compute virtual address of L3 PTE - mov r29=b0 // save b0 in case of nested fault - mov r31=pr // save pr -#ifdef CONFIG_SMP - mov r28=ar.ccv // save ar.ccv - ;; -1: ld8 r18=[r17] - ;; // avoid RAW on r18 - mov ar.ccv=r18 // set compare value for cmpxchg - or r25=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits - ;; - cmpxchg8.acq r26=[r17],r25,ar.ccv - mov r24=PAGE_SHIFT<<2 - ;; - cmp.eq p6,p7=r26,r18 - ;; -(p6) itc.d r25 // install updated PTE - ;; - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - - ld8 r18=[r17] // read PTE again - ;; - cmp.eq p6,p7=r18,r25 // is it same as the newly installed - ;; -(p7) ptc.l r16,r24 - mov b0=r29 // restore b0 - mov ar.ccv=r28 -#else - ;; -1: ld8 r18=[r17] - ;; // avoid RAW on r18 - or r18=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits - mov b0=r29 // restore b0 - ;; - st8 [r17]=r18 // store back updated PTE - itc.d r18 // install updated PTE -#endif - mov pr=r31,-1 // restore pr - rfi -END(dirty_bit) - - .org ia64_ivt+0x2400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) -ENTRY(iaccess_bit) -#ifdef XEN - mov r31=pr; - mov r16=cr.isr - mov r17=cr.ifa - mov r19=9 - movl r20=0x2400 - br.sptk.many fast_access_reflect;; -#endif - DBG_FAULT(9) - // Like Entry 8, except for instruction access - mov r16=cr.ifa // get the address that caused the fault - movl r30=1f // load continuation point in case of nested fault - mov r31=pr // save predicates -#ifdef CONFIG_ITANIUM - /* - * Erratum 10 (IFA may contain incorrect address) has "NoFix" status. - */ - mov r17=cr.ipsr - ;; - mov r18=cr.iip - tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set? - ;; -(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa -#endif /* CONFIG_ITANIUM */ - ;; - thash r17=r16 // compute virtual address of L3 PTE - mov r29=b0 // save b0 in case of nested fault) -#ifdef CONFIG_SMP - mov r28=ar.ccv // save ar.ccv - ;; -1: ld8 r18=[r17] - ;; - mov ar.ccv=r18 // set compare value for cmpxchg - or r25=_PAGE_A,r18 // set the accessed bit - ;; - cmpxchg8.acq r26=[r17],r25,ar.ccv - mov r24=PAGE_SHIFT<<2 - ;; - cmp.eq p6,p7=r26,r18 - ;; -(p6) itc.i r25 // install updated PTE - ;; - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - - ld8 r18=[r17] // read PTE again - ;; - cmp.eq p6,p7=r18,r25 // is it same as the newly installed - ;; -(p7) ptc.l r16,r24 - mov b0=r29 // restore b0 - mov ar.ccv=r28 -#else /* !CONFIG_SMP */ - ;; -1: ld8 r18=[r17] - ;; - or r18=_PAGE_A,r18 // set the accessed bit - mov b0=r29 // restore b0 - ;; - st8 [r17]=r18 // store back updated PTE - itc.i r18 // install updated PTE -#endif /* !CONFIG_SMP */ - mov pr=r31,-1 - rfi -END(iaccess_bit) - - .org ia64_ivt+0x2800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) -ENTRY(daccess_bit) -#ifdef XEN - mov r31=pr; - mov r16=cr.isr - mov r17=cr.ifa - mov r19=10 - movl r20=0x2800 - br.sptk.many fast_access_reflect;; -#endif - DBG_FAULT(10) - // Like Entry 8, except for data access - mov r16=cr.ifa // get the address that caused the fault - movl r30=1f // load continuation point in case of nested fault - ;; - thash r17=r16 // compute virtual address of L3 PTE - mov r31=pr - mov r29=b0 // save b0 in case of nested fault) -#ifdef CONFIG_SMP - mov r28=ar.ccv // save ar.ccv - ;; -1: ld8 r18=[r17] - ;; // avoid RAW on r18 - mov ar.ccv=r18 // set compare value for cmpxchg - or r25=_PAGE_A,r18 // set the dirty bit - ;; - cmpxchg8.acq r26=[r17],r25,ar.ccv - mov r24=PAGE_SHIFT<<2 - ;; - cmp.eq p6,p7=r26,r18 - ;; -(p6) itc.d r25 // install updated PTE - /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: - */ - dv_serialize_data - ;; - ld8 r18=[r17] // read PTE again - ;; - cmp.eq p6,p7=r18,r25 // is it same as the newly installed - ;; -(p7) ptc.l r16,r24 - mov ar.ccv=r28 -#else - ;; -1: ld8 r18=[r17] - ;; // avoid RAW on r18 - or r18=_PAGE_A,r18 // set the accessed bit - ;; - st8 [r17]=r18 // store back updated PTE - itc.d r18 // install updated PTE -#endif - mov b0=r29 // restore b0 - mov pr=r31,-1 - rfi -END(daccess_bit) - - .org ia64_ivt+0x2c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) -ENTRY(break_fault) - /* - * The streamlined system call entry/exit paths only save/restore the initial part - * of pt_regs. This implies that the callers of system-calls must adhere to the - * normal procedure calling conventions. - * - * Registers to be saved & restored: - * CR registers: cr.ipsr, cr.iip, cr.ifs - * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr - * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15 - * Registers to be restored only: - * r8-r11: output value from the system call. - * - * During system call exit, scratch registers (including r15) are modified/cleared - * to prevent leaking bits from kernel to user level. - */ - DBG_FAULT(11) -#ifdef XEN - mov r16=cr.isr - mov r17=cr.iim - mov r31=pr - ;; - movl r18=XSI_PSR_IC - ;; - ld8 r19=[r18] - ;; - cmp.eq p7,p0=r0,r17 // is this a psuedo-cover? -(p7) br.spnt.many dispatch_privop_fault - ;; - // if vpsr.ic is off, we have a hyperprivop - // A hyperprivop is hand-coded assembly with psr.ic off - // which means no calls, no use of r1-r15 and no memory accesses - // except to pinned addresses! - cmp4.eq p7,p0=r0,r19 -(p7) br.sptk.many fast_hyperprivop - ;; - movl r22=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r22 = [r22] - ;; - adds r22=IA64_VCPU_BREAKIMM_OFFSET,r22;; - ld4 r23=[r22];; - cmp4.eq p6,p7=r23,r17 // Xen-reserved breakimm? -(p6) br.spnt.many dispatch_break_fault - ;; - br.sptk.many fast_break_reflect - ;; -#endif - movl r16=THIS_CPU(cpu_kr)+IA64_KR_CURRENT_OFFSET;; - ld8 r16=[r16] - mov r17=cr.iim - mov r18=__IA64_BREAK_SYSCALL - mov r21=ar.fpsr - mov r29=cr.ipsr - mov r19=b6 - mov r25=ar.unat - mov r27=ar.rsc - mov r26=ar.pfs - mov r28=cr.iip -#ifndef XEN - mov r31=pr // prepare to save predicates -#endif - mov r20=r1 - ;; - adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 - cmp.eq p0,p7=r18,r17 // is this a system call? (p7 <- false, if so) -(p7) br.cond.spnt non_syscall - ;; - ld1 r17=[r16] // load current->thread.on_ustack flag - st1 [r16]=r0 // clear current->thread.on_ustack flag - add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT - ;; - invala - - /* adjust return address so we skip over the break instruction: */ - - extr.u r8=r29,41,2 // extract ei field from cr.ipsr - ;; - cmp.eq p6,p7=2,r8 // isr.ei==2? - mov r2=r1 // setup r2 for ia64_syscall_setup - ;; -(p6) mov r8=0 // clear ei to 0 -(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped -(p7) adds r8=1,r8 // increment ei to next slot - ;; - cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already? - dep r29=r8,r29,41,2 // insert new ei into cr.ipsr - ;; - - // switch from user to kernel RBS: - MINSTATE_START_SAVE_MIN_VIRT - br.call.sptk.many b7=ia64_syscall_setup - ;; - MINSTATE_END_SAVE_MIN_VIRT // switch to bank 1 - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - mov r3=NR_syscalls - 1 - ;; -(p15) ssm psr.i // restore psr.i - // p10==true means out registers are more than 8 or r15's Nat is true -(p10) br.cond.spnt.many ia64_ret_from_syscall - ;; - movl r16=sys_call_table - - adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 - movl r2=ia64_ret_from_syscall - ;; - shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) - cmp.leu p6,p7=r15,r3 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? - mov rp=r2 // set the real return addr - ;; -(p6) ld8 r20=[r20] // load address of syscall entry point -(p7) movl r20=sys_ni_syscall - - add r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld4 r2=[r2] // r2 = current_thread_info()->flags - ;; - and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit - ;; - cmp.eq p8,p0=r2,r0 - mov b6=r20 - ;; -(p8) br.call.sptk.many b6=b6 // ignore this return addr - br.cond.sptk ia64_trace_syscall - // NOT REACHED -END(break_fault) - - .org ia64_ivt+0x3000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) -ENTRY(interrupt) - DBG_FAULT(12) - mov r31=pr // prepare to save predicates - ;; -#ifdef XEN - mov r30=cr.ivr // pass cr.ivr as first arg - // FIXME: this is a hack... use cpuinfo.ksoftirqd because its - // not used anywhere else and we need a place to stash ivr and - // there's no registers available unused by SAVE_MIN/REST - movl r29=THIS_CPU(cpu_info)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; - st8 [r29]=r30;; - movl r28=slow_interrupt;; - mov r29=rp;; - mov rp=r28;; - br.cond.sptk.many fast_tick_reflect - ;; -slow_interrupt: - mov rp=r29;; -#endif - SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 - ssm psr.ic | PSR_DEFAULT_BITS - ;; - adds r3=8,r2 // set up second base pointer for SAVE_REST - srlz.i // ensure everybody knows psr.ic is back on - ;; - SAVE_REST - ;; - alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group -#ifdef XEN - movl out0=THIS_CPU(cpu_info)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; - ld8 out0=[out0];; -#else - mov out0=cr.ivr // pass cr.ivr as first arg -#endif - add out1=16,sp // pass pointer to pt_regs as second arg - ;; - srlz.d // make sure we see the effect of cr.ivr - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.call.sptk.many b6=ia64_handle_irq -END(interrupt) - - .org ia64_ivt+0x3400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3400 Entry 13 (size 64 bundles) Reserved - DBG_FAULT(13) - FAULT(13) - -#ifdef XEN - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... - -GLOBAL_ENTRY(dispatch_break_fault) - SAVE_MIN_WITH_COVER - ;; -dispatch_break_fault_post_save: - alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) - mov out0=cr.ifa - adds out1=16,sp - mov out2=cr.isr // FIXME: pity to make this slow access twice - mov out3=cr.iim // FIXME: pity to make this slow access twice - - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer - ;; - SAVE_REST - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.sptk.many ia64_prepare_handle_break -END(dispatch_break_fault) -#endif - - .org ia64_ivt+0x3800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3800 Entry 14 (size 64 bundles) Reserved - DBG_FAULT(14) - FAULT(14) - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - * - * ia64_syscall_setup() is a separate subroutine so that it can - * allocate stacked registers so it can safely demine any - * potential NaT values from the input registers. - * - * On entry: - * - executing on bank 0 or bank 1 register set (doesn't matter) - * - r1: stack pointer - * - r2: current task pointer - * - r3: preserved - * - r11: original contents (saved ar.pfs to be saved) - * - r12: original contents (sp to be saved) - * - r13: original contents (tp to be saved) - * - r15: original contents (syscall # to be saved) - * - r18: saved bsp (after switching to kernel stack) - * - r19: saved b6 - * - r20: saved r1 (gp) - * - r21: saved ar.fpsr - * - r22: kernel's register backing store base (krbs_base) - * - r23: saved ar.bspstore - * - r24: saved ar.rnat - * - r25: saved ar.unat - * - r26: saved ar.pfs - * - r27: saved ar.rsc - * - r28: saved cr.iip - * - r29: saved cr.ipsr - * - r31: saved pr - * - b0: original contents (to be saved) - * On exit: - * - executing on bank 1 registers - * - psr.ic enabled, interrupts restored - * - p10: TRUE if syscall is invoked with more than 8 out - * registers or r15's Nat is true - * - r1: kernel's gp - * - r3: preserved (same as on entry) - * - r8: -EINVAL if p10 is true - * - r12: points to kernel stack - * - r13: points to current task - * - p15: TRUE if interrupts need to be re-enabled - * - ar.fpsr: set to kernel settings - */ -GLOBAL_ENTRY(ia64_syscall_setup) -#ifndef XEN -#if PT(B6) != 0 -# error This code assumes that b6 is the first field in pt_regs. -#endif -#endif - st8 [r1]=r19 // save b6 - add r16=PT(CR_IPSR),r1 // initialize first base pointer - add r17=PT(R11),r1 // initialize second base pointer - ;; - alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable - st8 [r16]=r29,PT(AR_PFS)-PT(CR_IPSR) // save cr.ipsr - tnat.nz p8,p0=in0 - - st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11 - tnat.nz p9,p0=in1 -(pKStk) mov r18=r0 // make sure r18 isn't NaT - ;; - - st8 [r16]=r26,PT(CR_IFS)-PT(AR_PFS) // save ar.pfs - st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip - mov r28=b0 // save b0 (2 cyc) - ;; - - st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat - dep r19=0,r19,38,26 // clear all bits but 0..37 [I0] -(p8) mov in0=-1 - ;; - - st8 [r16]=r19,PT(AR_RNAT)-PT(CR_IFS) // store ar.pfs.pfm in cr.ifs - extr.u r11=r19,7,7 // I0 // get sol of ar.pfs - and r8=0x7f,r19 // A // get sof of ar.pfs - - st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc - tbit.nz p15,p0=r29,IA64_PSR_I_BIT // I0 -(p9) mov in1=-1 - ;; - -(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 - tnat.nz p10,p0=in2 - add r11=8,r11 - ;; -(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field -(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field - tnat.nz p11,p0=in3 - ;; -(p10) mov in2=-1 - tnat.nz p12,p0=in4 // [I0] -(p11) mov in3=-1 - ;; -(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat -(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore - shl r18=r18,16 // compute ar.rsc to be used for "loadrs" - ;; - st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates - st8 [r17]=r28,PT(R1)-PT(B0) // save b0 - tnat.nz p13,p0=in5 // [I0] - ;; - st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs" - st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1 -(p12) mov in4=-1 - ;; - -.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12 -.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13 -(p13) mov in5=-1 - ;; - st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr - tnat.nz p14,p0=in6 - cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8 - ;; - stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) -(p9) tnat.nz p10,p0=r15 - adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) - - st8.spill [r17]=r15 // save r15 - tnat.nz p8,p0=in7 - nop.i 0 - - mov r13=r2 // establish `current' - movl r1=__gp // establish kernel global pointer - ;; -(p14) mov in6=-1 -(p8) mov in7=-1 - nop.i 0 - - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - movl r17=FPSR_DEFAULT - ;; - mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value -(p10) mov r8=-EINVAL - br.ret.sptk.many b7 -END(ia64_syscall_setup) - - .org ia64_ivt+0x3c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3c00 Entry 15 (size 64 bundles) Reserved - DBG_FAULT(15) - FAULT(15) - - /* - * Squatting in this space ... - * - * This special case dispatcher for illegal operation faults allows preserved - * registers to be modified through a callback function (asm only) that is handed - * back from the fault handler in r8. Up to three arguments can be passed to the - * callback function by returning an aggregate with the callback as its first - * element, followed by the arguments. - */ -ENTRY(dispatch_illegal_op_fault) - SAVE_MIN_WITH_COVER - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer for SAVE_REST - ;; - alloc r14=ar.pfs,0,0,1,0 // must be first in insn group - mov out0=ar.ec - ;; - SAVE_REST - ;; - br.call.sptk.many rp=ia64_illegal_op_fault -.ret0: ;; - alloc r14=ar.pfs,0,0,3,0 // must be first in insn group - mov out0=r9 - mov out1=r10 - mov out2=r11 - movl r15=ia64_leave_kernel - ;; - mov rp=r15 - mov b6=r8 - ;; - cmp.ne p6,p0=0,r8 -(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel - br.sptk.many ia64_leave_kernel -END(dispatch_illegal_op_fault) - - .org ia64_ivt+0x4000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4000 Entry 16 (size 64 bundles) Reserved - DBG_FAULT(16) - FAULT(16) - -#ifdef XEN - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... - -ENTRY(dispatch_privop_fault) - SAVE_MIN_WITH_COVER - ;; - alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) - mov out0=cr.ifa - adds out1=16,sp - mov out2=cr.isr // FIXME: pity to make this slow access twice - mov out3=cr.itir - - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer - ;; - SAVE_REST - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.sptk.many ia64_prepare_handle_privop -END(dispatch_privop_fault) -#endif - - - .org ia64_ivt+0x4400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4400 Entry 17 (size 64 bundles) Reserved - DBG_FAULT(17) - FAULT(17) - -ENTRY(non_syscall) - SAVE_MIN_WITH_COVER - - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... - - alloc r14=ar.pfs,0,0,2,0 - mov out0=cr.iim - add out1=16,sp - adds r3=8,r2 // set up second base pointer for SAVE_REST - - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - movl r15=ia64_leave_kernel - ;; - SAVE_REST - mov rp=r15 - ;; - br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr -END(non_syscall) - - .org ia64_ivt+0x4800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4800 Entry 18 (size 64 bundles) Reserved - DBG_FAULT(18) - FAULT(18) - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - */ - -ENTRY(dispatch_unaligned_handler) - SAVE_MIN_WITH_COVER - ;; - alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) - mov out0=cr.ifa - adds out1=16,sp - - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer - ;; - SAVE_REST - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.sptk.many ia64_prepare_handle_unaligned -END(dispatch_unaligned_handler) - - .org ia64_ivt+0x4c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4c00 Entry 19 (size 64 bundles) Reserved - DBG_FAULT(19) - FAULT(19) - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - */ - -ENTRY(dispatch_to_fault_handler) - /* - * Input: - * psr.ic: off - * r19: fault vector number (e.g., 24 for General Exception) - * r31: contains saved predicates (pr) - */ - SAVE_MIN_WITH_COVER_R19 - alloc r14=ar.pfs,0,0,5,0 - mov out0=r15 - mov out1=cr.isr - mov out2=cr.ifa - mov out3=cr.iim - mov out4=cr.itir - ;; - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer for SAVE_REST - ;; - SAVE_REST - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.call.sptk.many b6=ia64_fault -END(dispatch_to_fault_handler) - -// -// --- End of long entries, Beginning of short entries -// - - .org ia64_ivt+0x5000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) -ENTRY(page_not_present) -#ifdef XEN - REFLECT(20) -#endif - DBG_FAULT(20) - mov r16=cr.ifa - rsm psr.dt - /* - * The Linux page fault handler doesn't expect non-present pages to be in - * the TLB. Flush the existing entry now, so we meet that expectation. - */ - mov r17=PAGE_SHIFT<<2 - ;; - ptc.l r16,r17 - ;; - mov r31=pr - srlz.d - br.sptk.many page_fault -END(page_not_present) - - .org ia64_ivt+0x5100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) -ENTRY(key_permission) -#ifdef XEN - REFLECT(21) -#endif - DBG_FAULT(21) - mov r16=cr.ifa - rsm psr.dt - mov r31=pr - ;; - srlz.d - br.sptk.many page_fault -END(key_permission) - - .org ia64_ivt+0x5200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) -ENTRY(iaccess_rights) -#ifdef XEN - REFLECT(22) -#endif - DBG_FAULT(22) - mov r16=cr.ifa - rsm psr.dt - mov r31=pr - ;; - srlz.d - br.sptk.many page_fault -END(iaccess_rights) - - .org ia64_ivt+0x5300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) -ENTRY(daccess_rights) -#ifdef XEN - mov r31=pr; - mov r16=cr.isr - mov r17=cr.ifa - mov r19=23 - movl r20=0x5300 - br.sptk.many fast_access_reflect;; -#endif - DBG_FAULT(23) - mov r16=cr.ifa - rsm psr.dt - mov r31=pr - ;; - srlz.d - br.sptk.many page_fault -END(daccess_rights) - - .org ia64_ivt+0x5400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) -ENTRY(general_exception) - DBG_FAULT(24) - mov r16=cr.isr - mov r31=pr - ;; -#ifdef XEN - cmp4.ge p6,p0=0x20,r16 -(p6) br.sptk.many dispatch_privop_fault -#else - cmp4.eq p6,p0=0,r16 -(p6) br.sptk.many dispatch_illegal_op_fault -#endif - ;; - mov r19=24 // fault number - br.sptk.many dispatch_to_fault_handler -END(general_exception) - - .org ia64_ivt+0x5500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) -ENTRY(disabled_fp_reg) -#ifdef XEN - REFLECT(25) -#endif - DBG_FAULT(25) - rsm psr.dfh // ensure we can access fph - ;; - srlz.d - mov r31=pr - mov r19=25 - br.sptk.many dispatch_to_fault_handler -END(disabled_fp_reg) - - .org ia64_ivt+0x5600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) -ENTRY(nat_consumption) -#ifdef XEN - REFLECT(26) -#endif - DBG_FAULT(26) - FAULT(26) -END(nat_consumption) - - .org ia64_ivt+0x5700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5700 Entry 27 (size 16 bundles) Speculation (40) -ENTRY(speculation_vector) -#ifdef XEN - // this probably need not reflect... - REFLECT(27) -#endif - DBG_FAULT(27) - /* - * A [f]chk.[as] instruction needs to take the branch to the recovery code but - * this part of the architecture is not implemented in hardware on some CPUs, such - * as Itanium. Thus, in general we need to emulate the behavior. IIM contains - * the relative target (not yet sign extended). So after sign extending it we - * simply add it to IIP. We also need to reset the EI field of the IPSR to zero, - * i.e., the slot to restart into. - * - * cr.imm contains zero_ext(imm21) - */ - mov r18=cr.iim - ;; - mov r17=cr.iip - shl r18=r18,43 // put sign bit in position (43=64-21) - ;; - - mov r16=cr.ipsr - shr r18=r18,39 // sign extend (39=43-4) - ;; - - add r17=r17,r18 // now add the offset - ;; - mov cr.iip=r17 - dep r16=0,r16,41,2 // clear EI - ;; - - mov cr.ipsr=r16 - ;; - - rfi // and go back -END(speculation_vector) - - .org ia64_ivt+0x5800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5800 Entry 28 (size 16 bundles) Reserved - DBG_FAULT(28) - FAULT(28) - - .org ia64_ivt+0x5900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) -ENTRY(debug_vector) -#ifdef XEN - REFLECT(29) -#endif - DBG_FAULT(29) - FAULT(29) -END(debug_vector) - - .org ia64_ivt+0x5a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) -ENTRY(unaligned_access) -#ifdef XEN - REFLECT(30) -#endif - DBG_FAULT(30) - mov r16=cr.ipsr - mov r31=pr // prepare to save predicates - ;; - br.sptk.many dispatch_unaligned_handler -END(unaligned_access) - - .org ia64_ivt+0x5b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) -ENTRY(unsupported_data_reference) -#ifdef XEN - REFLECT(31) -#endif - DBG_FAULT(31) - FAULT(31) -END(unsupported_data_reference) - - .org ia64_ivt+0x5c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) -ENTRY(floating_point_fault) -#ifdef XEN - REFLECT(32) -#endif - DBG_FAULT(32) - FAULT(32) -END(floating_point_fault) - - .org ia64_ivt+0x5d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) -ENTRY(floating_point_trap) -#ifdef XEN - REFLECT(33) -#endif - DBG_FAULT(33) - FAULT(33) -END(floating_point_trap) - - .org ia64_ivt+0x5e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) -ENTRY(lower_privilege_trap) -#ifdef XEN - REFLECT(34) -#endif - DBG_FAULT(34) - FAULT(34) -END(lower_privilege_trap) - - .org ia64_ivt+0x5f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) -ENTRY(taken_branch_trap) -#ifdef XEN - REFLECT(35) -#endif - DBG_FAULT(35) - FAULT(35) -END(taken_branch_trap) - - .org ia64_ivt+0x6000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) -ENTRY(single_step_trap) -#ifdef XEN - REFLECT(36) -#endif - DBG_FAULT(36) - FAULT(36) -END(single_step_trap) - - .org ia64_ivt+0x6100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6100 Entry 37 (size 16 bundles) Reserved - DBG_FAULT(37) - FAULT(37) - - .org ia64_ivt+0x6200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6200 Entry 38 (size 16 bundles) Reserved - DBG_FAULT(38) - FAULT(38) - - .org ia64_ivt+0x6300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6300 Entry 39 (size 16 bundles) Reserved - DBG_FAULT(39) - FAULT(39) - - .org ia64_ivt+0x6400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6400 Entry 40 (size 16 bundles) Reserved - DBG_FAULT(40) - FAULT(40) - - .org ia64_ivt+0x6500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6500 Entry 41 (size 16 bundles) Reserved - DBG_FAULT(41) - FAULT(41) - - .org ia64_ivt+0x6600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6600 Entry 42 (size 16 bundles) Reserved - DBG_FAULT(42) - FAULT(42) - - .org ia64_ivt+0x6700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6700 Entry 43 (size 16 bundles) Reserved - DBG_FAULT(43) - FAULT(43) - - .org ia64_ivt+0x6800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6800 Entry 44 (size 16 bundles) Reserved - DBG_FAULT(44) - FAULT(44) - - .org ia64_ivt+0x6900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) -ENTRY(ia32_exception) -#ifdef XEN - REFLECT(45) -#endif - DBG_FAULT(45) - FAULT(45) -END(ia32_exception) - - .org ia64_ivt+0x6a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) -ENTRY(ia32_intercept) -#ifdef XEN - REFLECT(46) -#endif - DBG_FAULT(46) -#ifdef CONFIG_IA32_SUPPORT - mov r31=pr - mov r16=cr.isr - ;; - extr.u r17=r16,16,8 // get ISR.code - mov r18=ar.eflag - mov r19=cr.iim // old eflag value - ;; - cmp.ne p6,p0=2,r17 -(p6) br.cond.spnt 1f // not a system flag fault - xor r16=r18,r19 - ;; - extr.u r17=r16,18,1 // get the eflags.ac bit - ;; - cmp.eq p6,p0=0,r17 -(p6) br.cond.spnt 1f // eflags.ac bit didn't change - ;; - mov pr=r31,-1 // restore predicate registers - rfi - -1: -#endif // CONFIG_IA32_SUPPORT - FAULT(46) -END(ia32_intercept) - - .org ia64_ivt+0x6b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) -ENTRY(ia32_interrupt) -#ifdef XEN - REFLECT(47) -#endif - DBG_FAULT(47) -#ifdef CONFIG_IA32_SUPPORT - mov r31=pr - br.sptk.many dispatch_to_ia32_handler -#else - FAULT(47) -#endif -END(ia32_interrupt) - - .org ia64_ivt+0x6c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6c00 Entry 48 (size 16 bundles) Reserved - DBG_FAULT(48) - FAULT(48) - - .org ia64_ivt+0x6d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6d00 Entry 49 (size 16 bundles) Reserved - DBG_FAULT(49) - FAULT(49) - - .org ia64_ivt+0x6e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6e00 Entry 50 (size 16 bundles) Reserved - DBG_FAULT(50) - FAULT(50) - - .org ia64_ivt+0x6f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6f00 Entry 51 (size 16 bundles) Reserved - DBG_FAULT(51) - FAULT(51) - - .org ia64_ivt+0x7000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7000 Entry 52 (size 16 bundles) Reserved - DBG_FAULT(52) - FAULT(52) - - .org ia64_ivt+0x7100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7100 Entry 53 (size 16 bundles) Reserved - DBG_FAULT(53) - FAULT(53) - - .org ia64_ivt+0x7200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7200 Entry 54 (size 16 bundles) Reserved - DBG_FAULT(54) - FAULT(54) - - .org ia64_ivt+0x7300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7300 Entry 55 (size 16 bundles) Reserved - DBG_FAULT(55) - FAULT(55) - - .org ia64_ivt+0x7400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7400 Entry 56 (size 16 bundles) Reserved - DBG_FAULT(56) - FAULT(56) - - .org ia64_ivt+0x7500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7500 Entry 57 (size 16 bundles) Reserved - DBG_FAULT(57) - FAULT(57) - - .org ia64_ivt+0x7600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7600 Entry 58 (size 16 bundles) Reserved - DBG_FAULT(58) - FAULT(58) - - .org ia64_ivt+0x7700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7700 Entry 59 (size 16 bundles) Reserved - DBG_FAULT(59) - FAULT(59) - - .org ia64_ivt+0x7800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7800 Entry 60 (size 16 bundles) Reserved - DBG_FAULT(60) - FAULT(60) - - .org ia64_ivt+0x7900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7900 Entry 61 (size 16 bundles) Reserved - DBG_FAULT(61) - FAULT(61) - - .org ia64_ivt+0x7a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7a00 Entry 62 (size 16 bundles) Reserved - DBG_FAULT(62) - FAULT(62) - - .org ia64_ivt+0x7b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7b00 Entry 63 (size 16 bundles) Reserved - DBG_FAULT(63) - FAULT(63) - - .org ia64_ivt+0x7c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7c00 Entry 64 (size 16 bundles) Reserved - DBG_FAULT(64) - FAULT(64) - - .org ia64_ivt+0x7d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7d00 Entry 65 (size 16 bundles) Reserved - DBG_FAULT(65) - FAULT(65) - - .org ia64_ivt+0x7e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7e00 Entry 66 (size 16 bundles) Reserved - DBG_FAULT(66) - FAULT(66) - - .org ia64_ivt+0x7f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7f00 Entry 67 (size 16 bundles) Reserved - DBG_FAULT(67) - FAULT(67) - -#ifdef XEN - .org ia64_ivt+0x8000 -GLOBAL_ENTRY(dispatch_reflection) - /* - * Input: - * psr.ic: off - * r19: intr type (offset into ivt, see ia64_int.h) - * r31: contains saved predicates (pr) - */ - SAVE_MIN_WITH_COVER_R19 - alloc r14=ar.pfs,0,0,5,0 - mov out4=r15 - mov out0=cr.ifa - adds out1=16,sp - mov out2=cr.isr - mov out3=cr.iim -// mov out3=cr.itir - - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i // restore psr.i - adds r3=8,r2 // set up second base pointer - ;; - SAVE_REST - movl r14=ia64_leave_kernel - ;; - mov rp=r14 - br.sptk.many ia64_prepare_handle_reflection -END(dispatch_reflection) - -#define SAVE_MIN_COVER_DONE DO_SAVE_MIN(,mov r30=cr.ifs,) - -// same as dispatch_break_fault except cover has already been done -GLOBAL_ENTRY(dispatch_slow_hyperprivop) - SAVE_MIN_COVER_DONE - ;; - br.sptk.many dispatch_break_fault_post_save -END(dispatch_slow_hyperprivop) -#endif - -#ifdef CONFIG_IA32_SUPPORT - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - */ - - // IA32 interrupt entry point - -ENTRY(dispatch_to_ia32_handler) - SAVE_MIN - ;; - mov r14=cr.isr - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i - adds r3=8,r2 // Base pointer for SAVE_REST - ;; - SAVE_REST - ;; - mov r15=0x80 - shr r14=r14,16 // Get interrupt number - ;; - cmp.ne p6,p0=r14,r15 -(p6) br.call.dpnt.many b6=non_ia32_syscall - - adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions - adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp - ;; - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - ld8 r8=[r14] // get r8 - ;; - st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) - ;; - alloc r15=ar.pfs,0,0,6,0 // must first in an insn group - ;; - ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=IA32_NR_syscalls - ;; - cmp.ltu.unc p6,p7=r8,r15 - ld4 out1=[r14],8 // r9 == ecx - ;; - ld4 out2=[r14],8 // r10 == edx - ;; - ld4 out0=[r14] // r11 == ebx - adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp - ;; - ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp - ;; - ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi - adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld4 out4=[r14] // r15 == edi - movl r16=ia32_syscall_table - ;; -(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number - ld4 r2=[r2] // r2 = current_thread_info()->flags - ;; - ld8 r16=[r16] - and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit - ;; - mov b6=r16 - movl r15=ia32_ret_from_syscall - cmp.eq p8,p0=r2,r0 - ;; - mov rp=r15 -(p8) br.call.sptk.many b6=b6 - br.cond.sptk ia32_trace_syscall - -non_ia32_syscall: - alloc r15=ar.pfs,0,0,2,0 - mov out0=r14 // interrupt # - add out1=16,sp // pointer to pt_regs - ;; // avoid WAW on CFM - br.call.sptk.many rp=ia32_bad_interrupt -.ret1: movl r15=ia64_leave_kernel - ;; - mov rp=r15 - br.ret.sptk.many rp -END(dispatch_to_ia32_handler) - -#endif /* CONFIG_IA32_SUPPORT */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/bitop.c --- a/xen/arch/ia64/linux/lib/bitop.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,88 +0,0 @@ -#include <linux/compiler.h> -#include <linux/types.h> -#include <asm/intrinsics.h> -#include <linux/module.h> -#include <linux/bitops.h> - -/* - * Find next zero bit in a bitmap reasonably efficiently.. - */ - -int __find_next_zero_bit (const void *addr, unsigned long size, unsigned long offset) -{ - unsigned long *p = ((unsigned long *) addr) + (offset >> 6); - unsigned long result = offset & ~63UL; - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 63UL; - if (offset) { - tmp = *(p++); - tmp |= ~0UL >> (64-offset); - if (size < 64) - goto found_first; - if (~tmp) - goto found_middle; - size -= 64; - result += 64; - } - while (size & ~63UL) { - if (~(tmp = *(p++))) - goto found_middle; - result += 64; - size -= 64; - } - if (!size) - return result; - tmp = *p; -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* any bits zero? */ - return result + size; /* nope */ -found_middle: - return result + ffz(tmp); -} -EXPORT_SYMBOL(__find_next_zero_bit); - -/* - * Find next bit in a bitmap reasonably efficiently.. - */ -int __find_next_bit(const void *addr, unsigned long size, unsigned long offset) -{ - unsigned long *p = ((unsigned long *) addr) + (offset >> 6); - unsigned long result = offset & ~63UL; - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 63UL; - if (offset) { - tmp = *(p++); - tmp &= ~0UL << offset; - if (size < 64) - goto found_first; - if (tmp) - goto found_middle; - size -= 64; - result += 64; - } - while (size & ~63UL) { - if ((tmp = *(p++))) - goto found_middle; - result += 64; - size -= 64; - } - if (!size) - return result; - tmp = *p; - found_first: - tmp &= ~0UL >> (64-size); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ - found_middle: - return result + __ffs(tmp); -} -EXPORT_SYMBOL(__find_next_bit); diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/clear_page.S --- a/xen/arch/ia64/linux/lib/clear_page.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,77 +0,0 @@ -/* - * Copyright (C) 1999-2002 Hewlett-Packard Co - * Stephane Eranian <eranian@xxxxxxxxxx> - * David Mosberger-Tang <davidm@xxxxxxxxxx> - * Copyright (C) 2002 Ken Chen <kenneth.w.chen@xxxxxxxxx> - * - * 1/06/01 davidm Tuned for Itanium. - * 2/12/02 kchen Tuned for both Itanium and McKinley - * 3/08/02 davidm Some more tweaking - */ -#include <linux/config.h> - -#include <asm/asmmacro.h> -#include <asm/page.h> - -#ifdef CONFIG_ITANIUM -# define L3_LINE_SIZE 64 // Itanium L3 line size -# define PREFETCH_LINES 9 // magic number -#else -# define L3_LINE_SIZE 128 // McKinley L3 line size -# define PREFETCH_LINES 12 // magic number -#endif - -#define saved_lc r2 -#define dst_fetch r3 -#define dst1 r8 -#define dst2 r9 -#define dst3 r10 -#define dst4 r11 - -#define dst_last r31 - -GLOBAL_ENTRY(clear_page) - .prologue - .regstk 1,0,0,0 - mov r16 = PAGE_SIZE/L3_LINE_SIZE-1 // main loop count, -1=repeat/until - .save ar.lc, saved_lc - mov saved_lc = ar.lc - - .body - mov ar.lc = (PREFETCH_LINES - 1) - mov dst_fetch = in0 - adds dst1 = 16, in0 - adds dst2 = 32, in0 - ;; -.fetch: stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE - adds dst3 = 48, in0 // executing this multiple times is harmless - br.cloop.sptk.few .fetch - ;; - addl dst_last = (PAGE_SIZE - PREFETCH_LINES*L3_LINE_SIZE), dst_fetch - mov ar.lc = r16 // one L3 line per iteration - adds dst4 = 64, in0 - ;; -#ifdef CONFIG_ITANIUM - // Optimized for Itanium -1: stf.spill.nta [dst1] = f0, 64 - stf.spill.nta [dst2] = f0, 64 - cmp.lt p8,p0=dst_fetch, dst_last - ;; -#else - // Optimized for McKinley -1: stf.spill.nta [dst1] = f0, 64 - stf.spill.nta [dst2] = f0, 64 - stf.spill.nta [dst3] = f0, 64 - stf.spill.nta [dst4] = f0, 128 - cmp.lt p8,p0=dst_fetch, dst_last - ;; - stf.spill.nta [dst1] = f0, 64 - stf.spill.nta [dst2] = f0, 64 -#endif - stf.spill.nta [dst3] = f0, 64 -(p8) stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE - br.cloop.sptk.few 1b - ;; - mov ar.lc = saved_lc // restore lc - br.ret.sptk.many rp -END(clear_page) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/copy_page_mck.S --- a/xen/arch/ia64/linux/lib/copy_page_mck.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,185 +0,0 @@ -/* - * McKinley-optimized version of copy_page(). - * - * Copyright (C) 2002 Hewlett-Packard Co - * David Mosberger <davidm@xxxxxxxxxx> - * - * Inputs: - * in0: address of target page - * in1: address of source page - * Output: - * no return value - * - * General idea: - * - use regular loads and stores to prefetch data to avoid consuming M-slot just for - * lfetches => good for in-cache performance - * - avoid l2 bank-conflicts by not storing into the same 16-byte bank within a single - * cycle - * - * Principle of operation: - * First, note that L1 has a line-size of 64 bytes and L2 a line-size of 128 bytes. - * To avoid secondary misses in L2, we prefetch both source and destination with a line-size - * of 128 bytes. When both of these lines are in the L2 and the first half of the - * source line is in L1, we start copying the remaining words. The second half of the - * source line is prefetched in an earlier iteration, so that by the time we start - * accessing it, it's also present in the L1. - * - * We use a software-pipelined loop to control the overall operation. The pipeline - * has 2*PREFETCH_DIST+K stages. The first PREFETCH_DIST stages are used for prefetching - * source cache-lines. The second PREFETCH_DIST stages are used for prefetching destination - * cache-lines, the last K stages are used to copy the cache-line words not copied by - * the prefetches. The four relevant points in the pipelined are called A, B, C, D: - * p[A] is TRUE if a source-line should be prefetched, p[B] is TRUE if a destination-line - * should be prefetched, p[C] is TRUE if the second half of an L2 line should be brought - * into L1D and p[D] is TRUE if a cacheline needs to be copied. - * - * This all sounds very complicated, but thanks to the modulo-scheduled loop support, - * the resulting code is very regular and quite easy to follow (once you get the idea). - * - * As a secondary optimization, the first 2*PREFETCH_DIST iterations are implemented - * as the separate .prefetch_loop. Logically, this loop performs exactly like the - * main-loop (.line_copy), but has all known-to-be-predicated-off instructions removed, - * so that each loop iteration is faster (again, good for cached case). - * - * When reading the code, it helps to keep the following picture in mind: - * - * word 0 word 1 - * +------+------+--- - * | v[x] | t1 | ^ - * | t2 | t3 | | - * | t4 | t5 | | - * | t6 | t7 | | 128 bytes - * | n[y] | t9 | | (L2 cache line) - * | t10 | t11 | | - * | t12 | t13 | | - * | t14 | t15 | v - * +------+------+--- - * - * Here, v[x] is copied by the (memory) prefetch. n[y] is loaded at p[C] - * to fetch the second-half of the L2 cache line into L1, and the tX words are copied in - * an order that avoids bank conflicts. - */ -#include <asm/asmmacro.h> -#include <asm/page.h> - -#define PREFETCH_DIST 8 // McKinley sustains 16 outstanding L2 misses (8 ld, 8 st) - -#define src0 r2 -#define src1 r3 -#define dst0 r9 -#define dst1 r10 -#define src_pre_mem r11 -#define dst_pre_mem r14 -#define src_pre_l2 r15 -#define dst_pre_l2 r16 -#define t1 r17 -#define t2 r18 -#define t3 r19 -#define t4 r20 -#define t5 t1 // alias! -#define t6 t2 // alias! -#define t7 t3 // alias! -#define t9 t5 // alias! -#define t10 t4 // alias! -#define t11 t7 // alias! -#define t12 t6 // alias! -#define t14 t10 // alias! -#define t13 r21 -#define t15 r22 - -#define saved_lc r23 -#define saved_pr r24 - -#define A 0 -#define B (PREFETCH_DIST) -#define C (B + PREFETCH_DIST) -#define D (C + 3) -#define N (D + 1) -#define Nrot ((N + 7) & ~7) - -GLOBAL_ENTRY(copy_page) - .prologue - alloc r8 = ar.pfs, 2, Nrot-2, 0, Nrot - - .rotr v[2*PREFETCH_DIST], n[D-C+1] - .rotp p[N] - - .save ar.lc, saved_lc - mov saved_lc = ar.lc - .save pr, saved_pr - mov saved_pr = pr - .body - - mov src_pre_mem = in1 - mov pr.rot = 0x10000 - mov ar.ec = 1 // special unrolled loop - - mov dst_pre_mem = in0 - mov ar.lc = 2*PREFETCH_DIST - 1 - - add src_pre_l2 = 8*8, in1 - add dst_pre_l2 = 8*8, in0 - add src0 = 8, in1 // first t1 src - add src1 = 3*8, in1 // first t3 src - add dst0 = 8, in0 // first t1 dst - add dst1 = 3*8, in0 // first t3 dst - mov t1 = (PAGE_SIZE/128) - (2*PREFETCH_DIST) - 1 - nop.m 0 - nop.i 0 - ;; - // same as .line_copy loop, but with all predicated-off instructions removed: -.prefetch_loop: -(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 -(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 - br.ctop.sptk .prefetch_loop - ;; - cmp.eq p16, p0 = r0, r0 // reset p16 to 1 (br.ctop cleared it to zero) - mov ar.lc = t1 // with 64KB pages, t1 is too big to fit in 8 bits! - mov ar.ec = N // # of stages in pipeline - ;; -.line_copy: -(p[D]) ld8 t2 = [src0], 3*8 // M0 -(p[D]) ld8 t4 = [src1], 3*8 // M1 -(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 prefetch dst from memory -(p[D]) st8 [dst_pre_l2] = n[D-C], 128 // M3 prefetch dst from L2 - ;; -(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 prefetch src from memory -(p[C]) ld8 n[0] = [src_pre_l2], 128 // M1 prefetch src from L2 -(p[D]) st8 [dst0] = t1, 8 // M2 -(p[D]) st8 [dst1] = t3, 8 // M3 - ;; -(p[D]) ld8 t5 = [src0], 8 -(p[D]) ld8 t7 = [src1], 3*8 -(p[D]) st8 [dst0] = t2, 3*8 -(p[D]) st8 [dst1] = t4, 3*8 - ;; -(p[D]) ld8 t6 = [src0], 3*8 -(p[D]) ld8 t10 = [src1], 8 -(p[D]) st8 [dst0] = t5, 8 -(p[D]) st8 [dst1] = t7, 3*8 - ;; -(p[D]) ld8 t9 = [src0], 3*8 -(p[D]) ld8 t11 = [src1], 3*8 -(p[D]) st8 [dst0] = t6, 3*8 -(p[D]) st8 [dst1] = t10, 8 - ;; -(p[D]) ld8 t12 = [src0], 8 -(p[D]) ld8 t14 = [src1], 8 -(p[D]) st8 [dst0] = t9, 3*8 -(p[D]) st8 [dst1] = t11, 3*8 - ;; -(p[D]) ld8 t13 = [src0], 4*8 -(p[D]) ld8 t15 = [src1], 4*8 -(p[D]) st8 [dst0] = t12, 8 -(p[D]) st8 [dst1] = t14, 8 - ;; -(p[D-1])ld8 t1 = [src0], 8 -(p[D-1])ld8 t3 = [src1], 8 -(p[D]) st8 [dst0] = t13, 4*8 -(p[D]) st8 [dst1] = t15, 4*8 - br.ctop.sptk .line_copy - ;; - mov ar.lc = saved_lc - mov pr = saved_pr, -1 - br.ret.sptk.many rp -END(copy_page) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/flush.S --- a/xen/arch/ia64/linux/lib/flush.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,61 +0,0 @@ -/* - * Cache flushing routines. - * - * Copyright (C) 1999-2001, 2005 Hewlett-Packard Co - * David Mosberger-Tang <davidm@xxxxxxxxxx> - * - * 05/28/05 Zoltan Menyhart Dynamic stride size - */ - -#include <asm/asmmacro.h> - - - /* - * flush_icache_range(start,end) - * - * Make i-cache(s) coherent with d-caches. - * - * Must deal with range from start to end-1 but nothing else (need to - * be careful not to touch addresses that may be unmapped). - * - * Note: "in0" and "in1" are preserved for debugging purposes. - */ -GLOBAL_ENTRY(flush_icache_range) - - .prologue - alloc r2=ar.pfs,2,0,0,0 - movl r3=ia64_i_cache_stride_shift - mov r21=1 - ;; - ld8 r20=[r3] // r20: stride shift - sub r22=in1,r0,1 // last byte address - ;; - shr.u r23=in0,r20 // start / (stride size) - shr.u r22=r22,r20 // (last byte address) / (stride size) - shl r21=r21,r20 // r21: stride size of the i-cache(s) - ;; - sub r8=r22,r23 // number of strides - 1 - shl r24=r23,r20 // r24: addresses for "fc.i" = - // "start" rounded down to stride boundary - .save ar.lc,r3 - mov r3=ar.lc // save ar.lc - ;; - - .body - mov ar.lc=r8 - ;; - /* - * 32 byte aligned loop, even number of (actually 2) bundles - */ -.Loop: fc.i r24 // issuable on M0 only - add r24=r21,r24 // we flush "stride size" bytes per iteration - nop.i 0 - br.cloop.sptk.few .Loop - ;; - sync.i - ;; - srlz.i - ;; - mov ar.lc=r3 // restore ar.lc - br.ret.sptk.many rp -END(flush_icache_range) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/idiv32.S --- a/xen/arch/ia64/linux/lib/idiv32.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang <davidm@xxxxxxxxxx> - * - * 32-bit integer division. - * - * This code is based on the application note entitled "Divide, Square Root - * and Remainder Algorithms for the IA-64 Architecture". This document - * is available as Intel document number 248725-002 or via the web at - * http://developer.intel.com/software/opensource/numerics/ - * - * For more details on the theory behind these algorithms, see "IA-64 - * and Elementary Functions" by Peter Markstein; HP Professional Books - * (http://www.hp.com/go/retailbooks/) - */ - -#include <asm/asmmacro.h> - -#ifdef MODULO -# define OP mod -#else -# define OP div -#endif - -#ifdef UNSIGNED -# define SGN u -# define EXTEND zxt4 -# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b -# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b -#else -# define SGN -# define EXTEND sxt4 -# define INT_TO_FP(a,b) fcvt.xf a=b -# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b -#endif - -#define PASTE1(a,b) a##b -#define PASTE(a,b) PASTE1(a,b) -#define NAME PASTE(PASTE(__,SGN),PASTE(OP,si3)) - -GLOBAL_ENTRY(NAME) - .regstk 2,0,0,0 - // Transfer inputs to FP registers. - mov r2 = 0xffdd // r2 = -34 + 65535 (fp reg format bias) - EXTEND in0 = in0 // in0 = a - EXTEND in1 = in1 // in1 = b - ;; - setf.sig f8 = in0 - setf.sig f9 = in1 -#ifdef MODULO - sub in1 = r0, in1 // in1 = -b -#endif - ;; - // Convert the inputs to FP, to avoid FP software-assist faults. - INT_TO_FP(f8, f8) - INT_TO_FP(f9, f9) - ;; - setf.exp f7 = r2 // f7 = 2^-34 - frcpa.s1 f6, p6 = f8, f9 // y0 = frcpa(b) - ;; -(p6) fmpy.s1 f8 = f8, f6 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f6, f1 // e0 = -b*y0 + 1 - ;; -#ifdef MODULO - setf.sig f9 = in1 // f9 = -b -#endif -(p6) fma.s1 f8 = f6, f8, f8 // q1 = e0*q0 + q0 -(p6) fma.s1 f6 = f6, f6, f7 // e1 = e0*e0 + 2^-34 - ;; -#ifdef MODULO - setf.sig f7 = in0 -#endif -(p6) fma.s1 f6 = f6, f8, f8 // q2 = e1*q1 + q1 - ;; - FP_TO_INT(f6, f6) // q = trunc(q2) - ;; -#ifdef MODULO - xma.l f6 = f6, f9, f7 // r = q*(-b) + a - ;; -#endif - getf.sig r8 = f6 // transfer result to result register - br.ret.sptk.many rp -END(NAME) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/idiv64.S --- a/xen/arch/ia64/linux/lib/idiv64.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,80 +0,0 @@ -/* - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@xxxxxxxxxx> - * - * 64-bit integer division. - * - * This code is based on the application note entitled "Divide, Square Root - * and Remainder Algorithms for the IA-64 Architecture". This document - * is available as Intel document number 248725-002 or via the web at - * http://developer.intel.com/software/opensource/numerics/ - * - * For more details on the theory behind these algorithms, see "IA-64 - * and Elementary Functions" by Peter Markstein; HP Professional Books - * (http://www.hp.com/go/retailbooks/) - */ - -#include <asm/asmmacro.h> - -#ifdef MODULO -# define OP mod -#else -# define OP div -#endif - -#ifdef UNSIGNED -# define SGN u -# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b -# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b -#else -# define SGN -# define INT_TO_FP(a,b) fcvt.xf a=b -# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b -#endif - -#define PASTE1(a,b) a##b -#define PASTE(a,b) PASTE1(a,b) -#define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) - -GLOBAL_ENTRY(NAME) - .regstk 2,0,0,0 - // Transfer inputs to FP registers. - setf.sig f8 = in0 - setf.sig f9 = in1 - ;; - // Convert the inputs to FP, to avoid FP software-assist faults. - INT_TO_FP(f8, f8) - INT_TO_FP(f9, f9) - ;; - frcpa.s1 f11, p6 = f8, f9 // y0 = frcpa(b) - ;; -(p6) fmpy.s1 f7 = f8, f11 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f11, f1 // e0 = -b*y0 + 1 - ;; -(p6) fma.s1 f10 = f7, f6, f7 // q1 = q0*e0 + q0 -(p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 - ;; -#ifdef MODULO - sub in1 = r0, in1 // in1 = -b -#endif -(p6) fma.s1 f10 = f10, f7, f10 // q2 = q1*e1 + q1 -(p6) fma.s1 f6 = f11, f6, f11 // y1 = y0*e0 + y0 - ;; -(p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 -(p6) fnma.s1 f7 = f9, f10, f8 // r = -b*q2 + a - ;; -#ifdef MODULO - setf.sig f8 = in0 // f8 = a - setf.sig f9 = in1 // f9 = -b -#endif -(p6) fma.s1 f11 = f7, f6, f10 // q3 = r*y2 + q2 - ;; - FP_TO_INT(f11, f11) // q = trunc(q3) - ;; -#ifdef MODULO - xma.l f11 = f11, f9, f8 // r = q*(-b) + a - ;; -#endif - getf.sig r8 = f11 // transfer result to result register - br.ret.sptk.many rp -END(NAME) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/memcpy_mck.S --- a/xen/arch/ia64/linux/lib/memcpy_mck.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,661 +0,0 @@ -/* - * Itanium 2-optimized version of memcpy and copy_user function - * - * Inputs: - * in0: destination address - * in1: source address - * in2: number of bytes to copy - * Output: - * 0 if success, or number of byte NOT copied if error occurred. - * - * Copyright (C) 2002 Intel Corp. - * Copyright (C) 2002 Ken Chen <kenneth.w.chen@xxxxxxxxx> - */ -#include <linux/config.h> -#include <asm/asmmacro.h> -#include <asm/page.h> - -#define EK(y...) EX(y) - -/* McKinley specific optimization */ - -#define retval r8 -#define saved_pfs r31 -#define saved_lc r10 -#define saved_pr r11 -#define saved_in0 r14 -#define saved_in1 r15 -#define saved_in2 r16 - -#define src0 r2 -#define src1 r3 -#define dst0 r17 -#define dst1 r18 -#define cnt r9 - -/* r19-r30 are temp for each code section */ -#define PREFETCH_DIST 8 -#define src_pre_mem r19 -#define dst_pre_mem r20 -#define src_pre_l2 r21 -#define dst_pre_l2 r22 -#define t1 r23 -#define t2 r24 -#define t3 r25 -#define t4 r26 -#define t5 t1 // alias! -#define t6 t2 // alias! -#define t7 t3 // alias! -#define n8 r27 -#define t9 t5 // alias! -#define t10 t4 // alias! -#define t11 t7 // alias! -#define t12 t6 // alias! -#define t14 t10 // alias! -#define t13 r28 -#define t15 r29 -#define tmp r30 - -/* defines for long_copy block */ -#define A 0 -#define B (PREFETCH_DIST) -#define C (B + PREFETCH_DIST) -#define D (C + 1) -#define N (D + 1) -#define Nrot ((N + 7) & ~7) - -/* alias */ -#define in0 r32 -#define in1 r33 -#define in2 r34 - -GLOBAL_ENTRY(memcpy) - and r28=0x7,in0 - and r29=0x7,in1 - mov f6=f0 - br.cond.sptk .common_code - ;; -END(memcpy) -GLOBAL_ENTRY(__copy_user) - .prologue -// check dest alignment - and r28=0x7,in0 - and r29=0x7,in1 - mov f6=f1 - mov saved_in0=in0 // save dest pointer - mov saved_in1=in1 // save src pointer - mov saved_in2=in2 // save len - ;; -.common_code: - cmp.gt p15,p0=8,in2 // check for small size - cmp.ne p13,p0=0,r28 // check dest alignment - cmp.ne p14,p0=0,r29 // check src alignment - add src0=0,in1 - sub r30=8,r28 // for .align_dest - mov retval=r0 // initialize return value - ;; - add dst0=0,in0 - add dst1=1,in0 // dest odd index - cmp.le p6,p0 = 1,r30 // for .align_dest -(p15) br.cond.dpnt .memcpy_short -(p13) br.cond.dpnt .align_dest -(p14) br.cond.dpnt .unaligned_src - ;; - -// both dest and src are aligned on 8-byte boundary -.aligned_src: - .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,3,Nrot-3,0,Nrot - .save pr, saved_pr - mov saved_pr=pr - - shr.u cnt=in2,7 // this much cache line - ;; - cmp.lt p6,p0=2*PREFETCH_DIST,cnt - cmp.lt p7,p8=1,cnt - .save ar.lc, saved_lc - mov saved_lc=ar.lc - .body - add cnt=-1,cnt - add src_pre_mem=0,in1 // prefetch src pointer - add dst_pre_mem=0,in0 // prefetch dest pointer - ;; -(p7) mov ar.lc=cnt // prefetch count -(p8) mov ar.lc=r0 -(p6) br.cond.dpnt .long_copy - ;; - -.prefetch: - lfetch.fault [src_pre_mem], 128 - lfetch.fault.excl [dst_pre_mem], 128 - br.cloop.dptk.few .prefetch - ;; - -.medium_copy: - and tmp=31,in2 // copy length after iteration - shr.u r29=in2,5 // number of 32-byte iteration - add dst1=8,dst0 // 2nd dest pointer - ;; - add cnt=-1,r29 // ctop iteration adjustment - cmp.eq p10,p0=r29,r0 // do we really need to loop? - add src1=8,src0 // 2nd src pointer - cmp.le p6,p0=8,tmp - ;; - cmp.le p7,p0=16,tmp - mov ar.lc=cnt // loop setup - cmp.eq p16,p17 = r0,r0 - mov ar.ec=2 -(p10) br.dpnt.few .aligned_src_tail - ;; - TEXT_ALIGN(32) -1: -EX(.ex_handler, (p16) ld8 r34=[src0],16) -EK(.ex_handler, (p16) ld8 r38=[src1],16) -EX(.ex_handler, (p17) st8 [dst0]=r33,16) -EK(.ex_handler, (p17) st8 [dst1]=r37,16) - ;; -EX(.ex_handler, (p16) ld8 r32=[src0],16) -EK(.ex_handler, (p16) ld8 r36=[src1],16) -EX(.ex_handler, (p16) st8 [dst0]=r34,16) -EK(.ex_handler, (p16) st8 [dst1]=r38,16) - br.ctop.dptk.few 1b - ;; - -.aligned_src_tail: -EX(.ex_handler, (p6) ld8 t1=[src0]) - mov ar.lc=saved_lc - mov ar.pfs=saved_pfs -EX(.ex_hndlr_s, (p7) ld8 t2=[src1],8) - cmp.le p8,p0=24,tmp - and r21=-8,tmp - ;; -EX(.ex_hndlr_s, (p8) ld8 t3=[src1]) -EX(.ex_handler, (p6) st8 [dst0]=t1) // store byte 1 - and in2=7,tmp // remaining length -EX(.ex_hndlr_d, (p7) st8 [dst1]=t2,8) // store byte 2 - add src0=src0,r21 // setting up src pointer - add dst0=dst0,r21 // setting up dest pointer - ;; -EX(.ex_handler, (p8) st8 [dst1]=t3) // store byte 3 - mov pr=saved_pr,-1 - br.dptk.many .memcpy_short - ;; - -/* code taken from copy_page_mck */ -.long_copy: - .rotr v[2*PREFETCH_DIST] - .rotp p[N] - - mov src_pre_mem = src0 - mov pr.rot = 0x10000 - mov ar.ec = 1 // special unrolled loop - - mov dst_pre_mem = dst0 - - add src_pre_l2 = 8*8, src0 - add dst_pre_l2 = 8*8, dst0 - ;; - add src0 = 8, src_pre_mem // first t1 src - mov ar.lc = 2*PREFETCH_DIST - 1 - shr.u cnt=in2,7 // number of lines - add src1 = 3*8, src_pre_mem // first t3 src - add dst0 = 8, dst_pre_mem // first t1 dst - add dst1 = 3*8, dst_pre_mem // first t3 dst - ;; - and tmp=127,in2 // remaining bytes after this block - add cnt = -(2*PREFETCH_DIST) - 1, cnt - // same as .line_copy loop, but with all predicated-off instructions removed: -.prefetch_loop: -EX(.ex_hndlr_lcpy_1, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 -EK(.ex_hndlr_lcpy_1, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 - br.ctop.sptk .prefetch_loop - ;; - cmp.eq p16, p0 = r0, r0 // reset p16 to 1 - mov ar.lc = cnt - mov ar.ec = N // # of stages in pipeline - ;; -.line_copy: -EX(.ex_handler, (p[D]) ld8 t2 = [src0], 3*8) // M0 -EK(.ex_handler, (p[D]) ld8 t4 = [src1], 3*8) // M1 -EX(.ex_handler_lcpy, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 prefetch dst from memory -EK(.ex_handler_lcpy, (p[D]) st8 [dst_pre_l2] = n8, 128) // M3 prefetch dst from L2 - ;; -EX(.ex_handler_lcpy, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 prefetch src from memory -EK(.ex_handler_lcpy, (p[C]) ld8 n8 = [src_pre_l2], 128) // M1 prefetch src from L2 -EX(.ex_handler, (p[D]) st8 [dst0] = t1, 8) // M2 -EK(.ex_handler, (p[D]) st8 [dst1] = t3, 8) // M3 - ;; -EX(.ex_handler, (p[D]) ld8 t5 = [src0], 8) -EK(.ex_handler, (p[D]) ld8 t7 = [src1], 3*8) -EX(.ex_handler, (p[D]) st8 [dst0] = t2, 3*8) -EK(.ex_handler, (p[D]) st8 [dst1] = t4, 3*8) - ;; -EX(.ex_handler, (p[D]) ld8 t6 = [src0], 3*8) -EK(.ex_handler, (p[D]) ld8 t10 = [src1], 8) -EX(.ex_handler, (p[D]) st8 [dst0] = t5, 8) -EK(.ex_handler, (p[D]) st8 [dst1] = t7, 3*8) - ;; -EX(.ex_handler, (p[D]) ld8 t9 = [src0], 3*8) -EK(.ex_handler, (p[D]) ld8 t11 = [src1], 3*8) -EX(.ex_handler, (p[D]) st8 [dst0] = t6, 3*8) -EK(.ex_handler, (p[D]) st8 [dst1] = t10, 8) - ;; -EX(.ex_handler, (p[D]) ld8 t12 = [src0], 8) -EK(.ex_handler, (p[D]) ld8 t14 = [src1], 8) -EX(.ex_handler, (p[D]) st8 [dst0] = t9, 3*8) -EK(.ex_handler, (p[D]) st8 [dst1] = t11, 3*8) - ;; -EX(.ex_handler, (p[D]) ld8 t13 = [src0], 4*8) -EK(.ex_handler, (p[D]) ld8 t15 = [src1], 4*8) -EX(.ex_handler, (p[D]) st8 [dst0] = t12, 8) -EK(.ex_handler, (p[D]) st8 [dst1] = t14, 8) - ;; -EX(.ex_handler, (p[C]) ld8 t1 = [src0], 8) -EK(.ex_handler, (p[C]) ld8 t3 = [src1], 8) -EX(.ex_handler, (p[D]) st8 [dst0] = t13, 4*8) -EK(.ex_handler, (p[D]) st8 [dst1] = t15, 4*8) - br.ctop.sptk .line_copy - ;; - - add dst0=-8,dst0 - add src0=-8,src0 - mov in2=tmp - .restore sp - br.sptk.many .medium_copy - ;; - -#define BLOCK_SIZE 128*32 -#define blocksize r23 -#define curlen r24 - -// dest is on 8-byte boundary, src is not. We need to do -// ld8-ld8, shrp, then st8. Max 8 byte copy per cycle. -.unaligned_src: - .prologue - .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,3,5,0,8 - .save ar.lc, saved_lc - mov saved_lc=ar.lc - .save pr, saved_pr - mov saved_pr=pr - .body -.4k_block: - mov saved_in0=dst0 // need to save all input arguments - mov saved_in2=in2 - mov blocksize=BLOCK_SIZE - ;; - cmp.lt p6,p7=blocksize,in2 - mov saved_in1=src0 - ;; -(p6) mov in2=blocksize - ;; - shr.u r21=in2,7 // this much cache line - shr.u r22=in2,4 // number of 16-byte iteration - and curlen=15,in2 // copy length after iteration - and r30=7,src0 // source alignment - ;; - cmp.lt p7,p8=1,r21 - add cnt=-1,r21 - ;; - - add src_pre_mem=0,src0 // prefetch src pointer - add dst_pre_mem=0,dst0 // prefetch dest pointer - and src0=-8,src0 // 1st src pointer -(p7) mov ar.lc = cnt -(p8) mov ar.lc = r0 - ;; - TEXT_ALIGN(32) -1: lfetch.fault [src_pre_mem], 128 - lfetch.fault.excl [dst_pre_mem], 128 - br.cloop.dptk.few 1b - ;; - - shladd dst1=r22,3,dst0 // 2nd dest pointer - shladd src1=r22,3,src0 // 2nd src pointer - cmp.eq p8,p9=r22,r0 // do we really need to loop? - cmp.le p6,p7=8,curlen; // have at least 8 byte remaining? - add cnt=-1,r22 // ctop iteration adjustment - ;; -EX(.ex_handler, (p9) ld8 r33=[src0],8) // loop primer -EK(.ex_handler, (p9) ld8 r37=[src1],8) -(p8) br.dpnt.few .noloop - ;; - -// The jump address is calculated based on src alignment. The COPYU -// macro below need to confine its size to power of two, so an entry -// can be caulated using shl instead of an expensive multiply. The -// size is then hard coded by the following #define to match the -// actual size. This make it somewhat tedious when COPYU macro gets -// changed and this need to be adjusted to match. -#define LOOP_SIZE 6 -1: - mov r29=ip // jmp_table thread - mov ar.lc=cnt - ;; - add r29=.jump_table - 1b - (.jmp1-.jump_table), r29 - shl r28=r30, LOOP_SIZE // jmp_table thread - mov ar.ec=2 // loop setup - ;; - add r29=r29,r28 // jmp_table thread - cmp.eq p16,p17=r0,r0 - ;; - mov b6=r29 // jmp_table thread - ;; - br.cond.sptk.few b6 - -// for 8-15 byte case -// We will skip the loop, but need to replicate the side effect -// that the loop produces. -.noloop: -EX(.ex_handler, (p6) ld8 r37=[src1],8) - add src0=8,src0 -(p6) shl r25=r30,3 - ;; -EX(.ex_handler, (p6) ld8 r27=[src1]) -(p6) shr.u r28=r37,r25 -(p6) sub r26=64,r25 - ;; -(p6) shl r27=r27,r26 - ;; -(p6) or r21=r28,r27 - -.unaligned_src_tail: -/* check if we have more than blocksize to copy, if so go back */ - cmp.gt p8,p0=saved_in2,blocksize - ;; -(p8) add dst0=saved_in0,blocksize -(p8) add src0=saved_in1,blocksize -(p8) sub in2=saved_in2,blocksize -(p8) br.dpnt .4k_block - ;; - -/* we have up to 15 byte to copy in the tail. - * part of work is already done in the jump table code - * we are at the following state. - * src side: - * - * xxxxxx xx <----- r21 has xxxxxxxx already - * -------- -------- -------- - * 0 8 16 - * ^ - * | - * src1 - * - * dst - * -------- -------- -------- - * ^ - * | - * dst1 - */ -EX(.ex_handler, (p6) st8 [dst1]=r21,8) // more than 8 byte to copy -(p6) add curlen=-8,curlen // update length - mov ar.pfs=saved_pfs - ;; - mov ar.lc=saved_lc - mov pr=saved_pr,-1 - mov in2=curlen // remaining length - mov dst0=dst1 // dest pointer - add src0=src1,r30 // forward by src alignment - ;; - -// 7 byte or smaller. -.memcpy_short: - cmp.le p8,p9 = 1,in2 - cmp.le p10,p11 = 2,in2 - cmp.le p12,p13 = 3,in2 - cmp.le p14,p15 = 4,in2 - add src1=1,src0 // second src pointer - add dst1=1,dst0 // second dest pointer - ;; - -EX(.ex_handler_short, (p8) ld1 t1=[src0],2) -EK(.ex_handler_short, (p10) ld1 t2=[src1],2) -(p9) br.ret.dpnt rp // 0 byte copy - ;; - -EX(.ex_handler_short, (p8) st1 [dst0]=t1,2) -EK(.ex_handler_short, (p10) st1 [dst1]=t2,2) -(p11) br.ret.dpnt rp // 1 byte copy - -EX(.ex_handler_short, (p12) ld1 t3=[src0],2) -EK(.ex_handler_short, (p14) ld1 t4=[src1],2) -(p13) br.ret.dpnt rp // 2 byte copy - ;; - - cmp.le p6,p7 = 5,in2 - cmp.le p8,p9 = 6,in2 - cmp.le p10,p11 = 7,in2 - -EX(.ex_handler_short, (p12) st1 [dst0]=t3,2) -EK(.ex_handler_short, (p14) st1 [dst1]=t4,2) -(p15) br.ret.dpnt rp // 3 byte copy - ;; - -EX(.ex_handler_short, (p6) ld1 t5=[src0],2) -EK(.ex_handler_short, (p8) ld1 t6=[src1],2) -(p7) br.ret.dpnt rp // 4 byte copy - ;; - -EX(.ex_handler_short, (p6) st1 [dst0]=t5,2) -EK(.ex_handler_short, (p8) st1 [dst1]=t6,2) -(p9) br.ret.dptk rp // 5 byte copy - -EX(.ex_handler_short, (p10) ld1 t7=[src0],2) -(p11) br.ret.dptk rp // 6 byte copy - ;; - -EX(.ex_handler_short, (p10) st1 [dst0]=t7,2) - br.ret.dptk rp // done all cases - - -/* Align dest to nearest 8-byte boundary. We know we have at - * least 7 bytes to copy, enough to crawl to 8-byte boundary. - * Actual number of byte to crawl depend on the dest alignment. - * 7 byte or less is taken care at .memcpy_short - - * src0 - source even index - * src1 - source odd index - * dst0 - dest even index - * dst1 - dest odd index - * r30 - distance to 8-byte boundary - */ - -.align_dest: - add src1=1,in1 // source odd index - cmp.le p7,p0 = 2,r30 // for .align_dest - cmp.le p8,p0 = 3,r30 // for .align_dest -EX(.ex_handler_short, (p6) ld1 t1=[src0],2) - cmp.le p9,p0 = 4,r30 // for .align_dest - cmp.le p10,p0 = 5,r30 - ;; -EX(.ex_handler_short, (p7) ld1 t2=[src1],2) -EK(.ex_handler_short, (p8) ld1 t3=[src0],2) - cmp.le p11,p0 = 6,r30 -EX(.ex_handler_short, (p6) st1 [dst0] = t1,2) - cmp.le p12,p0 = 7,r30 - ;; -EX(.ex_handler_short, (p9) ld1 t4=[src1],2) -EK(.ex_handler_short, (p10) ld1 t5=[src0],2) -EX(.ex_handler_short, (p7) st1 [dst1] = t2,2) -EK(.ex_handler_short, (p8) st1 [dst0] = t3,2) - ;; -EX(.ex_handler_short, (p11) ld1 t6=[src1],2) -EK(.ex_handler_short, (p12) ld1 t7=[src0],2) - cmp.eq p6,p7=r28,r29 -EX(.ex_handler_short, (p9) st1 [dst1] = t4,2) -EK(.ex_handler_short, (p10) st1 [dst0] = t5,2) - sub in2=in2,r30 - ;; -EX(.ex_handler_short, (p11) st1 [dst1] = t6,2) -EK(.ex_handler_short, (p12) st1 [dst0] = t7) - add dst0=in0,r30 // setup arguments - add src0=in1,r30 -(p6) br.cond.dptk .aligned_src -(p7) br.cond.dpnt .unaligned_src - ;; - -/* main loop body in jump table format */ -#define COPYU(shift) \ -1: \ -EX(.ex_handler, (p16) ld8 r32=[src0],8); /* 1 */ \ -EK(.ex_handler, (p16) ld8 r36=[src1],8); \ - (p17) shrp r35=r33,r34,shift;; /* 1 */ \ -EX(.ex_handler, (p6) ld8 r22=[src1]); /* common, prime for tail section */ \ - nop.m 0; \ - (p16) shrp r38=r36,r37,shift; \ -EX(.ex_handler, (p17) st8 [dst0]=r35,8); /* 1 */ \ -EK(.ex_handler, (p17) st8 [dst1]=r39,8); \ - br.ctop.dptk.few 1b;; \ - (p7) add src1=-8,src1; /* back out for <8 byte case */ \ - shrp r21=r22,r38,shift; /* speculative work */ \ - br.sptk.few .unaligned_src_tail /* branch out of jump table */ \ - ;; - TEXT_ALIGN(32) -.jump_table: - COPYU(8) // unaligned cases -.jmp1: - COPYU(16) - COPYU(24) - COPYU(32) - COPYU(40) - COPYU(48) - COPYU(56) - -#undef A -#undef B -#undef C -#undef D - -/* - * Due to lack of local tag support in gcc 2.x assembler, it is not clear which - * instruction failed in the bundle. The exception algorithm is that we - * first figure out the faulting address, then detect if there is any - * progress made on the copy, if so, redo the copy from last known copied - * location up to the faulting address (exclusive). In the copy_from_user - * case, remaining byte in kernel buffer will be zeroed. - * - * Take copy_from_user as an example, in the code there are multiple loads - * in a bundle and those multiple loads could span over two pages, the - * faulting address is calculated as page_round_down(max(src0, src1)). - * This is based on knowledge that if we can access one byte in a page, we - * can access any byte in that page. - * - * predicate used in the exception handler: - * p6-p7: direction - * p10-p11: src faulting addr calculation - * p12-p13: dst faulting addr calculation - */ - -#define A r19 -#define B r20 -#define C r21 -#define D r22 -#define F r28 - -#define memset_arg0 r32 -#define memset_arg2 r33 - -#define saved_retval loc0 -#define saved_rtlink loc1 -#define saved_pfs_stack loc2 - -.ex_hndlr_s: - add src0=8,src0 - br.sptk .ex_handler - ;; -.ex_hndlr_d: - add dst0=8,dst0 - br.sptk .ex_handler - ;; -.ex_hndlr_lcpy_1: - mov src1=src_pre_mem - mov dst1=dst_pre_mem - cmp.gtu p10,p11=src_pre_mem,saved_in1 - cmp.gtu p12,p13=dst_pre_mem,saved_in0 - ;; -(p10) add src0=8,saved_in1 -(p11) mov src0=saved_in1 -(p12) add dst0=8,saved_in0 -(p13) mov dst0=saved_in0 - br.sptk .ex_handler -.ex_handler_lcpy: - // in line_copy block, the preload addresses should always ahead - // of the other two src/dst pointers. Furthermore, src1/dst1 should - // always ahead of src0/dst0. - mov src1=src_pre_mem - mov dst1=dst_pre_mem -.ex_handler: - mov pr=saved_pr,-1 // first restore pr, lc, and pfs - mov ar.lc=saved_lc - mov ar.pfs=saved_pfs - ;; -.ex_handler_short: // fault occurred in these sections didn't change pr, lc, pfs - cmp.ltu p6,p7=saved_in0, saved_in1 // get the copy direction - cmp.ltu p10,p11=src0,src1 - cmp.ltu p12,p13=dst0,dst1 - fcmp.eq p8,p0=f6,f0 // is it memcpy? - mov tmp = dst0 - ;; -(p11) mov src1 = src0 // pick the larger of the two -(p13) mov dst0 = dst1 // make dst0 the smaller one -(p13) mov dst1 = tmp // and dst1 the larger one - ;; -(p6) dep F = r0,dst1,0,PAGE_SHIFT // usr dst round down to page boundary -(p7) dep F = r0,src1,0,PAGE_SHIFT // usr src round down to page boundary - ;; -(p6) cmp.le p14,p0=dst0,saved_in0 // no progress has been made on store -(p7) cmp.le p14,p0=src0,saved_in1 // no progress has been made on load - mov retval=saved_in2 -(p8) ld1 tmp=[src1] // force an oops for memcpy call -(p8) st1 [dst1]=r0 // force an oops for memcpy call -(p14) br.ret.sptk.many rp - -/* - * The remaining byte to copy is calculated as: - * - * A = (faulting_addr - orig_src) -> len to faulting ld address - * or - * (faulting_addr - orig_dst) -> len to faulting st address - * B = (cur_dst - orig_dst) -> len copied so far - * C = A - B -> len need to be copied - * D = orig_len - A -> len need to be zeroed - */ -(p6) sub A = F, saved_in0 -(p7) sub A = F, saved_in1 - clrrrb - ;; - alloc saved_pfs_stack=ar.pfs,3,3,3,0 - sub B = dst0, saved_in0 // how many byte copied so far - ;; - sub C = A, B - sub D = saved_in2, A - ;; - cmp.gt p8,p0=C,r0 // more than 1 byte? - add memset_arg0=saved_in0, A -(p6) mov memset_arg2=0 // copy_to_user should not call memset -(p7) mov memset_arg2=D // copy_from_user need to have kbuf zeroed - mov r8=0 - mov saved_retval = D - mov saved_rtlink = b0 - - add out0=saved_in0, B - add out1=saved_in1, B - mov out2=C -(p8) br.call.sptk.few b0=__copy_user // recursive call - ;; - - add saved_retval=saved_retval,r8 // above might return non-zero value - cmp.gt p8,p0=memset_arg2,r0 // more than 1 byte? - mov out0=memset_arg0 // *s - mov out1=r0 // c - mov out2=memset_arg2 // n -(p8) br.call.sptk.few b0=memset - ;; - - mov retval=saved_retval - mov ar.pfs=saved_pfs_stack - mov b0=saved_rtlink - br.ret.sptk.many rp - -/* end of McKinley specific optimization */ -END(__copy_user) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/memset.S --- a/xen/arch/ia64/linux/lib/memset.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,362 +0,0 @@ -/* Optimized version of the standard memset() function. - - Copyright (c) 2002 Hewlett-Packard Co/CERN - Sverre Jarp <Sverre.Jarp@xxxxxxx> - - Return: dest - - Inputs: - in0: dest - in1: value - in2: count - - The algorithm is fairly straightforward: set byte by byte until we - we get to a 16B-aligned address, then loop on 128 B chunks using an - early store as prefetching, then loop on 32B chucks, then clear remaining - words, finally clear remaining bytes. - Since a stf.spill f0 can store 16B in one go, we use this instruction - to get peak speed when value = 0. */ - -#include <asm/asmmacro.h> -#undef ret - -#define dest in0 -#define value in1 -#define cnt in2 - -#define tmp r31 -#define save_lc r30 -#define ptr0 r29 -#define ptr1 r28 -#define ptr2 r27 -#define ptr3 r26 -#define ptr9 r24 -#define loopcnt r23 -#define linecnt r22 -#define bytecnt r21 - -#define fvalue f6 - -// This routine uses only scratch predicate registers (p6 - p15) -#define p_scr p6 // default register for same-cycle branches -#define p_nz p7 -#define p_zr p8 -#define p_unalgn p9 -#define p_y p11 -#define p_n p12 -#define p_yy p13 -#define p_nn p14 - -#define MIN1 15 -#define MIN1P1HALF 8 -#define LINE_SIZE 128 -#define LSIZE_SH 7 // shift amount -#define PREF_AHEAD 8 - -GLOBAL_ENTRY(memset) -{ .mmi - .prologue - alloc tmp = ar.pfs, 3, 0, 0, 0 - lfetch.nt1 [dest] // - .save ar.lc, save_lc - mov.i save_lc = ar.lc - .body -} { .mmi - mov ret0 = dest // return value - cmp.ne p_nz, p_zr = value, r0 // use stf.spill if value is zero - cmp.eq p_scr, p0 = cnt, r0 -;; } -{ .mmi - and ptr2 = -(MIN1+1), dest // aligned address - and tmp = MIN1, dest // prepare to check for correct alignment - tbit.nz p_y, p_n = dest, 0 // Do we have an odd address? (M_B_U) -} { .mib - mov ptr1 = dest - mux1 value = value, @brcst // create 8 identical bytes in word -(p_scr) br.ret.dpnt.many rp // return immediately if count = 0 -;; } -{ .mib - cmp.ne p_unalgn, p0 = tmp, r0 // -} { .mib - sub bytecnt = (MIN1+1), tmp // NB: # of bytes to move is 1 higher than loopcnt - cmp.gt p_scr, p0 = 16, cnt // is it a minimalistic task? -(p_scr) br.cond.dptk.many .move_bytes_unaligned // go move just a few (M_B_U) -;; } -{ .mmi -(p_unalgn) add ptr1 = (MIN1+1), ptr2 // after alignment -(p_unalgn) add ptr2 = MIN1P1HALF, ptr2 // after alignment -(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 3 // should we do a st8 ? -;; } -{ .mib -(p_y) add cnt = -8, cnt // -(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 2 // should we do a st4 ? -} { .mib -(p_y) st8 [ptr2] = value,-4 // -(p_n) add ptr2 = 4, ptr2 // -;; } -{ .mib -(p_yy) add cnt = -4, cnt // -(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 1 // should we do a st2 ? -} { .mib -(p_yy) st4 [ptr2] = value,-2 // -(p_nn) add ptr2 = 2, ptr2 // -;; } -{ .mmi - mov tmp = LINE_SIZE+1 // for compare -(p_y) add cnt = -2, cnt // -(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 0 // should we do a st1 ? -} { .mmi - setf.sig fvalue=value // transfer value to FLP side -(p_y) st2 [ptr2] = value,-1 // -(p_n) add ptr2 = 1, ptr2 // -;; } - -{ .mmi -(p_yy) st1 [ptr2] = value // - cmp.gt p_scr, p0 = tmp, cnt // is it a minimalistic task? -} { .mbb -(p_yy) add cnt = -1, cnt // -(p_scr) br.cond.dpnt.many .fraction_of_line // go move just a few -;; } - -{ .mib - nop.m 0 - shr.u linecnt = cnt, LSIZE_SH -(p_zr) br.cond.dptk.many .l1b // Jump to use stf.spill -;; } - - TEXT_ALIGN(32) // --------------------- // L1A: store ahead into cache lines; fill later -{ .mmi - and tmp = -(LINE_SIZE), cnt // compute end of range - mov ptr9 = ptr1 // used for prefetching - and cnt = (LINE_SIZE-1), cnt // remainder -} { .mmi - mov loopcnt = PREF_AHEAD-1 // default prefetch loop - cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value -;; } -{ .mmi -(p_scr) add loopcnt = -1, linecnt // - add ptr2 = 8, ptr1 // start of stores (beyond prefetch stores) - add ptr1 = tmp, ptr1 // first address beyond total range -;; } -{ .mmi - add tmp = -1, linecnt // next loop count - mov.i ar.lc = loopcnt // -;; } -.pref_l1a: -{ .mib - stf8 [ptr9] = fvalue, 128 // Do stores one cache line apart - nop.i 0 - br.cloop.dptk.few .pref_l1a -;; } -{ .mmi - add ptr0 = 16, ptr2 // Two stores in parallel - mov.i ar.lc = tmp // -;; } -.l1ax: - { .mmi - stf8 [ptr2] = fvalue, 8 - stf8 [ptr0] = fvalue, 8 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 24 - stf8 [ptr0] = fvalue, 24 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 8 - stf8 [ptr0] = fvalue, 8 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 24 - stf8 [ptr0] = fvalue, 24 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 8 - stf8 [ptr0] = fvalue, 8 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 24 - stf8 [ptr0] = fvalue, 24 - ;; } - { .mmi - stf8 [ptr2] = fvalue, 8 - stf8 [ptr0] = fvalue, 32 - cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? - ;; } -{ .mmb - stf8 [ptr2] = fvalue, 24 -(p_scr) stf8 [ptr9] = fvalue, 128 - br.cloop.dptk.few .l1ax -;; } -{ .mbb - cmp.le p_scr, p0 = 8, cnt // just a few bytes left ? -(p_scr) br.cond.dpnt.many .fraction_of_line // Branch no. 2 - br.cond.dpnt.many .move_bytes_from_alignment // Branch no. 3 -;; } - - TEXT_ALIGN(32) -.l1b: // ------------------------------------ // L1B: store ahead into cache lines; fill later -{ .mmi - and tmp = -(LINE_SIZE), cnt // compute end of range - mov ptr9 = ptr1 // used for prefetching - and cnt = (LINE_SIZE-1), cnt // remainder -} { .mmi - mov loopcnt = PREF_AHEAD-1 // default prefetch loop - cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value -;; } -{ .mmi -(p_scr) add loopcnt = -1, linecnt - add ptr2 = 16, ptr1 // start of stores (beyond prefetch stores) - add ptr1 = tmp, ptr1 // first address beyond total range -;; } -{ .mmi - add tmp = -1, linecnt // next loop count - mov.i ar.lc = loopcnt -;; } -.pref_l1b: -{ .mib - stf.spill [ptr9] = f0, 128 // Do stores one cache line apart - nop.i 0 - br.cloop.dptk.few .pref_l1b -;; } -{ .mmi - add ptr0 = 16, ptr2 // Two stores in parallel - mov.i ar.lc = tmp -;; } -.l1bx: - { .mmi - stf.spill [ptr2] = f0, 32 - stf.spill [ptr0] = f0, 32 - ;; } - { .mmi - stf.spill [ptr2] = f0, 32 - stf.spill [ptr0] = f0, 32 - ;; } - { .mmi - stf.spill [ptr2] = f0, 32 - stf.spill [ptr0] = f0, 64 - cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? - ;; } -{ .mmb - stf.spill [ptr2] = f0, 32 -(p_scr) stf.spill [ptr9] = f0, 128 - br.cloop.dptk.few .l1bx -;; } -{ .mib - cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? -(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // -;; } - -.fraction_of_line: -{ .mib - add ptr2 = 16, ptr1 - shr.u loopcnt = cnt, 5 // loopcnt = cnt / 32 -;; } -{ .mib - cmp.eq p_scr, p0 = loopcnt, r0 - add loopcnt = -1, loopcnt -(p_scr) br.cond.dpnt.many .store_words -;; } -{ .mib - and cnt = 0x1f, cnt // compute the remaining cnt - mov.i ar.lc = loopcnt -;; } - TEXT_ALIGN(32) -.l2: // ------------------------------------ // L2A: store 32B in 2 cycles -{ .mmb - stf8 [ptr1] = fvalue, 8 - stf8 [ptr2] = fvalue, 8 -;; } { .mmb - stf8 [ptr1] = fvalue, 24 - stf8 [ptr2] = fvalue, 24 - br.cloop.dptk.many .l2 -;; } -.store_words: -{ .mib - cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? -(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // Branch -;; } - -{ .mmi - stf8 [ptr1] = fvalue, 8 // store - cmp.le p_y, p_n = 16, cnt - add cnt = -8, cnt // subtract -;; } -{ .mmi -(p_y) stf8 [ptr1] = fvalue, 8 // store -(p_y) cmp.le.unc p_yy, p_nn = 16, cnt -(p_y) add cnt = -8, cnt // subtract -;; } -{ .mmi // store -(p_yy) stf8 [ptr1] = fvalue, 8 -(p_yy) add cnt = -8, cnt // subtract -;; } - -.move_bytes_from_alignment: -{ .mib - cmp.eq p_scr, p0 = cnt, r0 - tbit.nz.unc p_y, p0 = cnt, 2 // should we terminate with a st4 ? -(p_scr) br.cond.dpnt.few .restore_and_exit -;; } -{ .mib -(p_y) st4 [ptr1] = value,4 - tbit.nz.unc p_yy, p0 = cnt, 1 // should we terminate with a st2 ? -;; } -{ .mib -(p_yy) st2 [ptr1] = value,2 - tbit.nz.unc p_y, p0 = cnt, 0 // should we terminate with a st1 ? -;; } - -{ .mib -(p_y) st1 [ptr1] = value -;; } -.restore_and_exit: -{ .mib - nop.m 0 - mov.i ar.lc = save_lc - br.ret.sptk.many rp -;; } - -.move_bytes_unaligned: -{ .mmi - .pred.rel "mutex",p_y, p_n - .pred.rel "mutex",p_yy, p_nn -(p_n) cmp.le p_yy, p_nn = 4, cnt -(p_y) cmp.le p_yy, p_nn = 5, cnt -(p_n) add ptr2 = 2, ptr1 -} { .mmi -(p_y) add ptr2 = 3, ptr1 -(p_y) st1 [ptr1] = value, 1 // fill 1 (odd-aligned) byte [15, 14 (or less) left] -(p_y) add cnt = -1, cnt -;; } -{ .mmi -(p_yy) cmp.le.unc p_y, p0 = 8, cnt - add ptr3 = ptr1, cnt // prepare last store - mov.i ar.lc = save_lc -} { .mmi -(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes -(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [11, 10 (o less) left] -(p_yy) add cnt = -4, cnt -;; } -{ .mmi -(p_y) cmp.le.unc p_yy, p0 = 8, cnt - add ptr3 = -1, ptr3 // last store - tbit.nz p_scr, p0 = cnt, 1 // will there be a st2 at the end ? -} { .mmi -(p_y) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes -(p_y) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [7, 6 (or less) left] -(p_y) add cnt = -4, cnt -;; } -{ .mmi -(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes -(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [3, 2 (or less) left] - tbit.nz p_y, p0 = cnt, 0 // will there be a st1 at the end ? -} { .mmi -(p_yy) add cnt = -4, cnt -;; } -{ .mmb -(p_scr) st2 [ptr1] = value // fill 2 (aligned) bytes -(p_y) st1 [ptr3] = value // fill last byte (using ptr3) - br.ret.sptk.many rp -} -END(memset) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/linux/lib/strlen.S --- a/xen/arch/ia64/linux/lib/strlen.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,192 +0,0 @@ -/* - * - * Optimized version of the standard strlen() function - * - * - * Inputs: - * in0 address of string - * - * Outputs: - * ret0 the number of characters in the string (0 if empty string) - * does not count the \0 - * - * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Stephane Eranian <eranian@xxxxxxxxxx> - * - * 09/24/99 S.Eranian add speculation recovery code - */ - -#include <asm/asmmacro.h> - -// -// -// This is an enhanced version of the basic strlen. it includes a combination -// of compute zero index (czx), parallel comparisons, speculative loads and -// loop unroll using rotating registers. -// -// General Ideas about the algorithm: -// The goal is to look at the string in chunks of 8 bytes. -// so we need to do a few extra checks at the beginning because the -// string may not be 8-byte aligned. In this case we load the 8byte -// quantity which includes the start of the string and mask the unused -// bytes with 0xff to avoid confusing czx. -// We use speculative loads and software pipelining to hide memory -// latency and do read ahead safely. This way we defer any exception. -// -// Because we don't want the kernel to be relying on particular -// settings of the DCR register, we provide recovery code in case -// speculation fails. The recovery code is going to "redo" the work using -// only normal loads. If we still get a fault then we generate a -// kernel panic. Otherwise we return the strlen as usual. -// -// The fact that speculation may fail can be caused, for instance, by -// the DCR.dm bit being set. In this case TLB misses are deferred, i.e., -// a NaT bit will be set if the translation is not present. The normal -// load, on the other hand, will cause the translation to be inserted -// if the mapping exists. -// -// It should be noted that we execute recovery code only when we need -// to use the data that has been speculatively loaded: we don't execute -// recovery code on pure read ahead data. -// -// Remarks: -// - the cmp r0,r0 is used as a fast way to initialize a predicate -// register to 1. This is required to make sure that we get the parallel -// compare correct. -// -// - we don't use the epilogue counter to exit the loop but we need to set -// it to zero beforehand. -// -// - after the loop we must test for Nat values because neither the -// czx nor cmp instruction raise a NaT consumption fault. We must be -// careful not to look too far for a Nat for which we don't care. -// For instance we don't need to look at a NaT in val2 if the zero byte -// was in val1. -// -// - Clearly performance tuning is required. -// -// -// -#define saved_pfs r11 -#define tmp r10 -#define base r16 -#define orig r17 -#define saved_pr r18 -#define src r19 -#define mask r20 -#define val r21 -#define val1 r22 -#define val2 r23 - -GLOBAL_ENTRY(strlen) - .prologue - .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 - - .rotr v[2], w[2] // declares our 4 aliases - - extr.u tmp=in0,0,3 // tmp=least significant 3 bits - mov orig=in0 // keep trackof initial byte address - dep src=0,in0,0,3 // src=8byte-aligned in0 address - .save pr, saved_pr - mov saved_pr=pr // preserve predicates (rotation) - ;; - - .body - - ld8 v[1]=[src],8 // must not speculate: can fail here - shl tmp=tmp,3 // multiply by 8bits/byte - mov mask=-1 // our mask - ;; - ld8.s w[1]=[src],8 // speculatively load next - cmp.eq p6,p0=r0,r0 // sets p6 to true for cmp.and - sub tmp=64,tmp // how many bits to shift our mask on the right - ;; - shr.u mask=mask,tmp // zero enough bits to hold v[1] valuable part - mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) - ;; - add base=-16,src // keep track of aligned base - or v[1]=v[1],mask // now we have a safe initial byte pattern - ;; -1: - ld8.s v[0]=[src],8 // speculatively load next - czx1.r val1=v[1] // search 0 byte from right - czx1.r val2=w[1] // search 0 byte from right following 8bytes - ;; - ld8.s w[0]=[src],8 // speculatively load next to next - cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 - cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 -(p6) br.wtop.dptk 1b // loop until p6 == 0 - ;; - // - // We must return try the recovery code iff - // val1_is_nat || (val1==8 && val2_is_nat) - // - // XXX Fixme - // - there must be a better way of doing the test - // - cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) - tnat.nz p6,p7=val1 // test NaT on val1 -(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT - ;; - // - // if we come here p7 is true, i.e., initialized for // cmp - // - cmp.eq.and p7,p0=8,val1// val1==8? - tnat.nz.and p7,p0=val2 // test NaT if val2 -(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT - ;; -(p8) mov val1=val2 // the other test got us out of the loop -(p8) adds src=-16,src // correct position when 3 ahead -(p9) adds src=-24,src // correct position when 4 ahead - ;; - sub ret0=src,orig // distance from base - sub tmp=8,val1 // which byte in word - mov pr=saved_pr,0xffffffffffff0000 - ;; - sub ret0=ret0,tmp // adjust - mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.many rp // end of normal execution - - // - // Outlined recovery code when speculation failed - // - // This time we don't use speculation and rely on the normal exception - // mechanism. that's why the loop is not as good as the previous one - // because read ahead is not possible - // - // IMPORTANT: - // Please note that in the case of strlen() as opposed to strlen_user() - // we don't use the exception mechanism, as this function is not - // supposed to fail. If that happens it means we have a bug and the - // code will cause of kernel fault. - // - // XXX Fixme - // - today we restart from the beginning of the string instead - // of trying to continue where we left off. - // -.recover: - ld8 val=[base],8 // will fail if unrecoverable fault - ;; - or val=val,mask // remask first bytes - cmp.eq p0,p6=r0,r0 // nullify first ld8 in loop - ;; - // - // ar.ec is still zero here - // -2: -(p6) ld8 val=[base],8 // will fail if unrecoverable fault - ;; - czx1.r val1=val // search 0 byte from right - ;; - cmp.eq p6,p0=8,val1 // val1==8 ? -(p6) br.wtop.dptk 2b // loop until p6 == 0 - ;; // (avoid WAW on p63) - sub ret0=base,orig // distance from base - sub tmp=8,val1 - mov pr=saved_pr,0xffffffffffff0000 - ;; - sub ret0=ret0,tmp // length=now - back -1 - mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.many rp // end of successful recovery code -END(strlen) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/mm.c --- a/xen/arch/ia64/mm.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,152 +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@xxxxxxxxx) - * - * 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 - */ -#ifdef CONFIG_VTI -int 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 = redistribute_rid(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; - } - thash_purge_and_insert(hcb, &entry); - }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; -} -#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/mm_init.c --- a/xen/arch/ia64/mm_init.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,547 +0,0 @@ -/* - * Initialize MMU support. - * - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang <davidm@xxxxxxxxxx> - */ -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#ifdef XEN -#include <xen/sched.h> -#endif -#include <linux/bootmem.h> -#include <linux/efi.h> -#include <linux/elf.h> -#include <linux/mm.h> -#include <linux/mmzone.h> -#include <linux/module.h> -#ifndef XEN -#include <linux/personality.h> -#endif -#include <linux/reboot.h> -#include <linux/slab.h> -#include <linux/swap.h> -#ifndef XEN -#include <linux/proc_fs.h> -#endif - -#ifndef XEN -#include <asm/a.out.h> -#endif -#include <asm/bitops.h> -#include <asm/dma.h> -#ifndef XEN -#include <asm/ia32.h> -#endif -#include <asm/io.h> -#include <asm/machvec.h> -#include <asm/numa.h> -#include <asm/patch.h> -#include <asm/pgalloc.h> -#include <asm/sal.h> -#include <asm/sections.h> -#include <asm/system.h> -#include <asm/tlb.h> -#include <asm/uaccess.h> -#include <asm/unistd.h> -#include <asm/mca.h> - -#ifndef XEN -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -#endif - -extern void ia64_tlb_init (void); - -unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; - -#ifdef CONFIG_VIRTUAL_MEM_MAP -unsigned long vmalloc_end = VMALLOC_END_INIT; -EXPORT_SYMBOL(vmalloc_end); -struct page *vmem_map; -EXPORT_SYMBOL(vmem_map); -#endif - -static int pgt_cache_water[2] = { 25, 50 }; - -struct page *zero_page_memmap_ptr; /* map entry for zero page */ -EXPORT_SYMBOL(zero_page_memmap_ptr); - -#ifdef XEN -void *high_memory; -EXPORT_SYMBOL(high_memory); - -///////////////////////////////////////////// -// following from linux-2.6.7/mm/mmap.c -/* description of effects of mapping type and prot in current implementation. - * this is due to the limited x86 page protection hardware. The expected - * behavior is in parens: - * - * map_type prot - * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC - * MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes - * w: (no) no w: (no) no w: (yes) yes w: (no) no - * x: (no) no x: (no) yes x: (no) yes x: (yes) yes - * - * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes - * w: (no) no w: (no) no w: (copy) copy w: (no) no - * x: (no) no x: (no) yes x: (no) yes x: (yes) yes - * - */ -pgprot_t protection_map[16] = { - __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, - __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 -}; - -void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) -{ - printf("insert_vm_struct: called, not implemented yet\n"); -} - -///////////////////////////////////////////// -//following from linux/mm/memory.c - -#ifndef __ARCH_HAS_4LEVEL_HACK -/* - * Allocate page upper directory. - * - * We've already handled the fast-path in-line, and we own the - * page table lock. - * - * On a two-level or three-level page table, this ends up actually being - * entirely optimized away. - */ -pud_t fastcall *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) -{ - pud_t *new; - - spin_unlock(&mm->page_table_lock); - new = pud_alloc_one(mm, address); - spin_lock(&mm->page_table_lock); - if (!new) - return NULL; - - /* - * Because we dropped the lock, we should re-check the - * entry, as somebody else could have populated it.. - */ - if (pgd_present(*pgd)) { - pud_free(new); - goto out; - } - pgd_populate(mm, pgd, new); - out: - return pud_offset(pgd, address); -} - -/* - * Allocate page middle directory. - * - * We've already handled the fast-path in-line, and we own the - * page table lock. - * - * On a two-level page table, this ends up actually being entirely - * optimized away. - */ -pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) -{ - pmd_t *new; - - spin_unlock(&mm->page_table_lock); - new = pmd_alloc_one(mm, address); - spin_lock(&mm->page_table_lock); - if (!new) - return NULL; - - /* - * Because we dropped the lock, we should re-check the - * entry, as somebody else could have populated it.. - */ - if (pud_present(*pud)) { - pmd_free(new); - goto out; - } - pud_populate(mm, pud, new); - out: - return pmd_offset(pud, address); -} -#endif - -pte_t fastcall * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address) -{ - if (!pmd_present(*pmd)) { - struct page *new; - - spin_unlock(&mm->page_table_lock); - new = pte_alloc_one(mm, address); - spin_lock(&mm->page_table_lock); - if (!new) - return NULL; - - /* - * Because we dropped the lock, we should re-check the - * entry, as somebody else could have populated it.. - */ - if (pmd_present(*pmd)) { - pte_free(new); - goto out; - } - inc_page_state(nr_page_table_pages); - pmd_populate(mm, pmd, new); - } -out: - return pte_offset_map(pmd, address); -} -///////////////////////////////////////////// -#endif /* XEN */ - -void -update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) -{ - unsigned long addr; - struct page *page; - - if (!pte_exec(pte)) - return; /* not an executable page... */ - - page = pte_page(pte); - /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ - addr = (unsigned long) page_address(page); - - if (test_bit(PG_arch_1, &page->flags)) - return; /* i-cache is already coherent with d-cache */ - - flush_icache_range(addr, addr + PAGE_SIZE); - set_bit(PG_arch_1, &page->flags); /* mark page as clean */ -} - -inline void -ia64_set_rbs_bot (void) -{ -#ifdef XEN - unsigned stack_size = MAX_USER_STACK_SIZE; -#else - unsigned long stack_size = current->rlim[RLIMIT_STACK].rlim_max & -16; -#endif - - if (stack_size > MAX_USER_STACK_SIZE) - stack_size = MAX_USER_STACK_SIZE; - current->arch._thread.rbs_bot = STACK_TOP - stack_size; -} - -/* - * This performs some platform-dependent address space initialization. - * On IA-64, we want to setup the VM area for the register backing - * store (which grows upwards) and install the gateway page which is - * used for signal trampolines, etc. - */ -void -ia64_init_addr_space (void) -{ -#ifdef XEN -printf("ia64_init_addr_space: called, not implemented\n"); -#else - struct vm_area_struct *vma; - - ia64_set_rbs_bot(); - - /* - * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore - * the problem. When the process attempts to write to the register backing store - * for the first time, it will get a SEGFAULT in this case. - */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (vma) { - memset(vma, 0, sizeof(*vma)); - vma->vm_mm = current->mm; - vma->vm_start = current->arch._thread.rbs_bot & PAGE_MASK; - vma->vm_end = vma->vm_start + PAGE_SIZE; - vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; - vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; - insert_vm_struct(current->mm, vma); - } - - /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ - if (!(current->personality & MMAP_PAGE_ZERO)) { - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (vma) { - memset(vma, 0, sizeof(*vma)); - vma->vm_mm = current->mm; - vma->vm_end = PAGE_SIZE; - vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); - vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; - insert_vm_struct(current->mm, vma); - } - } -#endif -} - -setup_gate (void) -{ - printk("setup_gate not-implemented.\n"); -} - -void __devinit -ia64_mmu_init (void *my_cpu_data) -{ - unsigned long psr, pta, impl_va_bits; - extern void __devinit tlb_init (void); - int cpu; - -#ifdef CONFIG_DISABLE_VHPT -# define VHPT_ENABLE_BIT 0 -#else -# define VHPT_ENABLE_BIT 1 -#endif - - /* Pin mapping for percpu area into TLB */ - psr = ia64_clear_ic(); - ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), - PERCPU_PAGE_SHIFT); - - ia64_set_psr(psr); - ia64_srlz_i(); - - /* - * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped - * address space. The IA-64 architecture guarantees that at least 50 bits of - * virtual address space are implemented but if we pick a large enough page size - * (e.g., 64KB), the mapped address space is big enough that it will overlap with - * VMLPT. I assume that once we run on machines big enough to warrant 64KB pages, - * IMPL_VA_MSB will be significantly bigger, so this is unlikely to become a - * problem in practice. Alternatively, we could truncate the top of the mapped - * address space to not permit mappings that would overlap with the VMLPT. - * --davidm 00/12/06 - */ -# define pte_bits 3 -# define mapped_space_bits (3*(PAGE_SHIFT - pte_bits) + PAGE_SHIFT) - /* - * The virtual page table has to cover the entire implemented address space within - * a region even though not all of this space may be mappable. The reason for - * this is that the Access bit and Dirty bit fault handlers perform - * non-speculative accesses to the virtual page table, so the address range of the - * virtual page table itself needs to be covered by virtual page table. - */ -# define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) -# define POW2(n) (1ULL << (n)) - - impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); - - if (impl_va_bits < 51 || impl_va_bits > 61) - panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); - -#ifdef XEN - vhpt_init(); -#endif -#if 0 - /* place the VMLPT at the end of each page-table mapped region: */ - pta = POW2(61) - POW2(vmlpt_bits); - - if (POW2(mapped_space_bits) >= pta) - panic("mm/init: overlap between virtually mapped linear page table and " - "mapped kernel space!"); - /* - * Set the (virtually mapped linear) page table address. Bit - * 8 selects between the short and long format, bits 2-7 the - * size of the table, and bit 0 whether the VHPT walker is - * enabled. - */ - ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); -#endif - ia64_tlb_init(); - -#ifdef CONFIG_HUGETLB_PAGE - ia64_set_rr(HPAGE_REGION_BASE, HPAGE_SHIFT << 2); - ia64_srlz_d(); -#endif - - cpu = smp_processor_id(); - -#ifndef XEN - /* mca handler uses cr.lid as key to pick the right entry */ - ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID); - - /* insert this percpu data information into our list for MCA recovery purposes */ - ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); - /* Also save per-cpu tlb flush recipe for use in physical mode mca handler */ - ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base; - ia64_mca_tlb_list[cpu].ptce_count[0] = local_cpu_data->ptce_count[0]; - ia64_mca_tlb_list[cpu].ptce_count[1] = local_cpu_data->ptce_count[1]; - ia64_mca_tlb_list[cpu].ptce_stride[0] = local_cpu_data->ptce_stride[0]; - ia64_mca_tlb_list[cpu].ptce_stride[1] = local_cpu_data->ptce_stride[1]; -#endif -} - -#ifdef CONFIG_VIRTUAL_MEM_MAP - -int -create_mem_map_page_table (u64 start, u64 end, void *arg) -{ - unsigned long address, start_page, end_page; - struct page *map_start, *map_end; - int node; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); - map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); - - start_page = (unsigned long) map_start & PAGE_MASK; - end_page = PAGE_ALIGN((unsigned long) map_end); - node = paddr_to_nid(__pa(start)); - - for (address = start_page; address < end_page; address += PAGE_SIZE) { - pgd = pgd_offset_k(address); - if (pgd_none(*pgd)) - pgd_populate(&init_mm, pgd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); - pmd = pmd_offset(pgd, address); - - if (pmd_none(*pmd)) - pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); - pte = pte_offset_kernel(pmd, address); - - if (pte_none(*pte)) - set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)) >> PAGE_SHIFT, - PAGE_KERNEL)); - } - return 0; -} - -struct memmap_init_callback_data { - struct page *start; - struct page *end; - int nid; - unsigned long zone; -}; - -static int -virtual_memmap_init (u64 start, u64 end, void *arg) -{ - struct memmap_init_callback_data *args; - struct page *map_start, *map_end; - - args = (struct memmap_init_callback_data *) arg; - - map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); - map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); - - if (map_start < args->start) - map_start = args->start; - if (map_end > args->end) - map_end = args->end; - - /* - * We have to initialize "out of bounds" struct page elements that fit completely - * on the same pages that were allocated for the "in bounds" elements because they - * may be referenced later (and found to be "reserved"). - */ - map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page); - map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end) - / sizeof(struct page)); - - if (map_start < map_end) - memmap_init_zone(map_start, (unsigned long) (map_end - map_start), - args->nid, args->zone, page_to_pfn(map_start)); - return 0; -} - -void -memmap_init (struct page *start, unsigned long size, int nid, - unsigned long zone, unsigned long start_pfn) -{ - if (!vmem_map) - memmap_init_zone(start, size, nid, zone, start_pfn); - else { - struct memmap_init_callback_data args; - - args.start = start; - args.end = start + size; - args.nid = nid; - args.zone = zone; - - efi_memmap_walk(virtual_memmap_init, &args); - } -} - -int -ia64_pfn_valid (unsigned long pfn) -{ - char byte; - struct page *pg = pfn_to_page(pfn); - - return (__get_user(byte, (char *) pg) == 0) - && ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK)) - || (__get_user(byte, (char *) (pg + 1) - 1) == 0)); -} -EXPORT_SYMBOL(ia64_pfn_valid); - -int -find_largest_hole (u64 start, u64 end, void *arg) -{ - u64 *max_gap = arg; - - static u64 last_end = PAGE_OFFSET; - - /* NOTE: this algorithm assumes efi memmap table is ordered */ - -#ifdef XEN -//printf("find_largest_hole: start=%lx,end=%lx,max_gap=%lx\n",start,end,*(unsigned long *)arg); -#endif - if (*max_gap < (start - last_end)) - *max_gap = start - last_end; - last_end = end; -#ifdef XEN -//printf("find_largest_hole2: max_gap=%lx,last_end=%lx\n",*max_gap,last_end); -#endif - return 0; -} -#endif /* CONFIG_VIRTUAL_MEM_MAP */ - -static int -count_reserved_pages (u64 start, u64 end, void *arg) -{ - unsigned long num_reserved = 0; - unsigned long *count = arg; - - for (; start < end; start += PAGE_SIZE) - if (PageReserved(virt_to_page(start))) - ++num_reserved; - *count += num_reserved; - return 0; -} - -/* - * Boot command-line option "nolwsys" can be used to disable the use of any light-weight - * system call handler. When this option is in effect, all fsyscalls will end up bubbling - * down into the kernel and calling the normal (heavy-weight) syscall handler. This is - * useful for performance testing, but conceivably could also come in handy for debugging - * purposes. - */ - -static int nolwsys; - -static int __init -nolwsys_setup (char *s) -{ - nolwsys = 1; - return 1; -} - -__setup("nolwsys", nolwsys_setup); - -void -mem_init (void) -{ -#ifdef CONFIG_PCI - /* - * This needs to be called _after_ the command line has been parsed but _before_ - * any drivers that may need the PCI DMA interface are initialized or bootmem has - * been freed. - */ - platform_dma_init(); -#endif - -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/mmio.c --- a/xen/arch/ia64/mmio.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,515 +0,0 @@ - -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * mmio.c: MMIO emulation components. - * Copyright (c) 2004, Intel Corporation. - * - * 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. - * - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - * Kun Tian (Kevin Tian) (Kevin.tian@xxxxxxxxx) - */ - -#include <linux/sched.h> -#include <asm/tlb.h> -#include <asm/vmx_mm_def.h> -#include <asm/gcc_intrin.h> -#include <linux/interrupt.h> -#include <asm/vmx_vcpu.h> -#include <asm/privop.h> -#include <asm/types.h> -#include <public/io/ioreq.h> -#include <asm/mm.h> -#include <asm/vmx.h> - -/* -struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) -{ - int i; - for (i=0; mio_base[i].iot != NOT_IO; i++ ) { - if ( gpa >= mio_base[i].start && gpa <= mio_base[i].end ) - return &mio_base[i]; - } - return NULL; -} -*/ - -#define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) -#define PIB_OFST_INTA 0x1E0000 -#define PIB_OFST_XTP 0x1E0008 - -static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) -{ - switch (pib_off) { - case PIB_OFST_INTA: - panic("Undefined write on PIB INTA\n"); - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4 /* UC */) { - vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src; - } - else { - panic("Undefined write on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 0x4 /* UC */ ) { - panic("Undefined IPI-LHF write with s %d, ma %d!\n", s, ma); - } - else { - write_ipi(vcpu, pib_off, *(uint64_t *)src); - // TODO for SM-VP - } - } - else { // upper half - printf("IPI-UHF write %lx\n",pib_off); - panic("Not support yet for SM-VP\n"); - } - break; - } -} - -static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) -{ - switch (pib_off) { - case PIB_OFST_INTA: - // todo --- emit on processor system bus. - if ( s == 1 && ma == 4) { // 1 byte load - // TODO: INTA read from IOSAPIC - } - else { - panic("Undefined read on PIB INTA\n"); - } - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4) { - *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp; - } - else { - panic("Undefined read on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 4 ) { - panic("Undefined IPI-LHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printf("IPI-LHF read %lx\n",pib_off); -#endif - *(uint64_t *)dest = 0; // TODO for SM-VP - } - } - else { // upper half - if ( s != 1 || ma != 4 ) { - panic("Undefined PIB-UHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printf("IPI-UHF read %lx\n",pib_off); -#endif - *(uint8_t *)dest = 0; // TODO for SM-VP - } - } - break; - } -} - -static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) -{ - struct vcpu *v = current; - vcpu_iodata_t *vio; - ioreq_t *p; - unsigned long addr; - - vio = get_vio(v->domain, v->vcpu_id); - if (vio == 0) { - panic("bad shared page: %lx", (unsigned long)vio); - } - p = &vio->vp_ioreq; - p->addr = pa; - p->size = s; - p->count = 1; - p->dir = dir; - if(dir==IOREQ_WRITE) //write; - p->u.data = *val; - p->pdata_valid = 0; - p->port_mm = 1; - p->df = 0; - - set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); - p->state = STATE_IOREQ_READY; - evtchn_send(iopacket_port(v->domain)); - vmx_wait_io(); - if(dir==IOREQ_READ){ //read - *val=p->u.data; - } - return; -} -#define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3)) - -static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) -{ - struct vcpu *v = current; - vcpu_iodata_t *vio; - ioreq_t *p; - unsigned long addr; - - vio = get_vio(v->domain, v->vcpu_id); - if (vio == 0) { - panic("bad shared page: %lx"); - } - p = &vio->vp_ioreq; - p->addr = TO_LEGACY_IO(pa&0x3ffffffUL); - p->size = s; - p->count = 1; - p->dir = dir; - if(dir==IOREQ_WRITE) //write; - p->u.data = *val; - p->pdata_valid = 0; - p->port_mm = 0; - p->df = 0; - - set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); - p->state = STATE_IOREQ_READY; - evtchn_send(iopacket_port(v->domain)); - - vmx_wait_io(); - if(dir==IOREQ_READ){ //read - *val=p->u.data; - } -#ifdef DEBUG_PCI - if(dir==IOREQ_WRITE) - if(p->addr == 0xcf8UL) - printk("Write 0xcf8, with val [0x%lx]\n", p->u.data); - else - if(p->addr == 0xcfcUL) - printk("Read 0xcfc, with val [0x%lx]\n", p->u.data); -#endif //DEBUG_PCI - return; -} - -static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir) -{ - struct virutal_platform_def *v_plat; - //mmio_type_t iot; - unsigned long iot; - iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT); - v_plat = vmx_vcpu_get_plat(vcpu); - - switch (iot) { - case GPFN_PIB: - if(!dir) - pib_write(vcpu, dest, src_pa - v_plat->pib_base, s, ma); - else - pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); - break; - case GPFN_GFW: - break; - case GPFN_IOSAPIC: - case GPFN_FRAME_BUFFER: - case GPFN_LOW_MMIO: - low_mmio_access(vcpu, src_pa, dest, s, dir); - break; - case GPFN_LEGACY_IO: - legacy_io_access(vcpu, src_pa, dest, s, dir); - break; - default: - panic("Bad I/O access\n"); - break; - } - return; -} - -/* - * Read or write data in guest virtual address mode. - */ -/* -void -memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic("Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)dest, vtlb->ps); - mmio_write (vcpu, src, pa, s, vtlb->ma); -} - - -void -memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa = (uint64_t)dest; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_write (vcpu, src, pa, s, ma); -} - -void -memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic("Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)src, vtlb->ps); - - mmio_read(vcpu, pa, dest, s, vtlb->ma); -} - -void -memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa = (uint64_t)src; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_read(vcpu, pa, dest, s, ma); -} -*/ - - -/* - * Deliver IPI message. (Only U-VP is supported now) - * offset: address offset to IPI space. - * value: deliver value. - */ -static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) -{ -#ifdef IPI_DEBUG - printf ("deliver_ipi %lx %lx\n",dm,vector); -#endif - switch ( dm ) { - case 0: // INT - vmx_vcpu_pend_interrupt (vcpu, vector); - break; - case 2: // PMI - // TODO -- inject guest PMI - panic ("Inject guest PMI!\n"); - break; - case 4: // NMI - vmx_vcpu_pend_interrupt (vcpu, 2); - break; - case 5: // INIT - // TODO -- inject guest INIT - panic ("Inject guest INIT!\n"); - break; - case 7: // ExtINT - vmx_vcpu_pend_interrupt (vcpu, 0); - break; - case 1: - case 3: - case 6: - default: - panic ("Deliver reserved IPI!\n"); - break; - } -} - -/* - * TODO: Use hash table for the lookup. - */ -static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) -{ - int i; - VCPU *vcpu; - LID lid; - for (i=0; i<MAX_VIRT_CPUS; i++) { - vcpu = d->vcpu[i]; - if (!vcpu) - continue; - lid.val = VPD_CR(vcpu, lid); - if ( lid.id == id && lid.eid == eid ) { - return vcpu; - } - } - return NULL; -} - -/* - * execute write IPI op. - */ -static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) -{ - VCPU *target_cpu; - - target_cpu = lid_2_vcpu(vcpu->domain, - ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); - if ( target_cpu == NULL ) panic("Unknown IPI cpu\n"); - if ( target_cpu == vcpu ) { - // IPI to self - deliver_ipi (vcpu, ((ipi_d_t)value).dm, - ((ipi_d_t)value).vector); - return 1; - } - else { - // TODO: send Host IPI to inject guest SMP IPI interruption - panic ("No SM-VP supported!\n"); - return 0; - } -} - - -/* - dir 1: read 0:write - inst_type 0:integer 1:floating point - */ -extern IA64_BUNDLE __vmx_get_domain_bundle(u64 iip); -#define SL_INTEGER 0 // store/load interger -#define SL_FLOATING 1 // store/load floating - -void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) -{ - REGS *regs; - IA64_BUNDLE bundle; - int slot, dir, inst_type; - size_t size; - u64 data, value,post_update, slot1a, slot1b, temp; - INST64 inst; - regs=vcpu_regs(vcpu); - bundle = __vmx_get_domain_bundle(regs->cr_iip); - slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; - if (!slot) inst.inst = bundle.slot0; - else if (slot == 1){ - slot1a=bundle.slot1a; - slot1b=bundle.slot1b; - inst.inst =slot1a + (slot1b<<18); - } - else if (slot == 2) inst.inst = bundle.slot2; - - - // Integer Load/Store - if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){ - inst_type = SL_INTEGER; // - size=(inst.M1.x6&0x3); - if((inst.M1.x6>>2)>0xb){ // write - dir=IOREQ_WRITE; //write - vmx_vcpu_get_gr(vcpu,inst.M4.r2,&data); - }else if((inst.M1.x6>>2)<0xb){ // read - dir=IOREQ_READ; - vmx_vcpu_get_gr(vcpu,inst.M1.r1,&value); - } - } - // Integer Load + Reg update - else if(inst.M2.major==4&&inst.M2.m==1&&inst.M2.x==0){ - inst_type = SL_INTEGER; - dir = IOREQ_READ; //write - size = (inst.M2.x6&0x3); - vmx_vcpu_get_gr(vcpu,inst.M2.r1,&value); - vmx_vcpu_get_gr(vcpu,inst.M2.r3,&temp); - vmx_vcpu_get_gr(vcpu,inst.M2.r2,&post_update); - temp += post_update; - vmx_vcpu_set_gr(vcpu,inst.M2.r3,temp,0); - } - // Integer Load/Store + Imm update - else if(inst.M3.major==5){ - inst_type = SL_INTEGER; // - size=(inst.M3.x6&0x3); - if((inst.M5.x6>>2)>0xb){ // write - dir=IOREQ_WRITE; //write - vmx_vcpu_get_gr(vcpu,inst.M5.r2,&data); - vmx_vcpu_get_gr(vcpu,inst.M5.r3,&temp); - post_update = (inst.M5.i<<7)+inst.M5.imm7; - if(inst.M5.s) - temp -= post_update; - else - temp += post_update; - vmx_vcpu_set_gr(vcpu,inst.M5.r3,temp,0); - - }else if((inst.M3.x6>>2)<0xb){ // read - dir=IOREQ_READ; - vmx_vcpu_get_gr(vcpu,inst.M3.r1,&value); - vmx_vcpu_get_gr(vcpu,inst.M3.r3,&temp); - post_update = (inst.M3.i<<7)+inst.M3.imm7; - if(inst.M3.s) - temp -= post_update; - else - temp += post_update; - vmx_vcpu_set_gr(vcpu,inst.M3.r3,temp,0); - - } - } - // Floating-point Load/Store -// else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){ -// inst_type=SL_FLOATING; //fp -// dir=IOREQ_READ; -// size=3; //ldfd -// } - else{ - printf("This memory access instruction can't be emulated two: %lx\n ",inst.inst); - while(1); - } - - size = 1 << size; - if(dir==IOREQ_WRITE){ - mmio_access(vcpu, padr, &data, size, ma, dir); - }else{ - mmio_access(vcpu, padr, &data, size, ma, dir); - if(size==0) - data = (value & 0xffffffffffffff00U) | (data & 0xffU); - else if(size==1) - data = (value & 0xffffffffffff0000U) | (data & 0xffffU); - else if(size==2) - data = (value & 0xffffffff00000000U) | (data & 0xffffffffU); - - if(inst_type==SL_INTEGER){ //gp - vmx_vcpu_set_gr(vcpu,inst.M1.r1,data,0); - }else{ - panic("Don't support ldfd now !"); -/* switch(inst.M6.f1){ - - case 6: - regs->f6=(struct ia64_fpreg)data; - case 7: - regs->f7=(struct ia64_fpreg)data; - case 8: - regs->f8=(struct ia64_fpreg)data; - case 9: - regs->f9=(struct ia64_fpreg)data; - case 10: - regs->f10=(struct ia64_fpreg)data; - case 11: - regs->f11=(struct ia64_fpreg)data; - default : - ia64_ldfs(inst.M6.f1,&data); - } -*/ - } - } - vmx_vcpu_increment_iip(vcpu); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/pal_emul.c --- a/xen/arch/ia64/pal_emul.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,280 +0,0 @@ -/* - * PAL/SAL call delegation - * - * Copyright (c) 2004 Li Susie <susie.li@xxxxxxxxx> - * Copyright (c) 2005 Yu Ke <ke.yu@xxxxxxxxx> - * - * 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. - */ - -#include <asm/vmx_vcpu.h> - -static void -get_pal_parameters (VCPU *vcpu, UINT64 *gr29, - UINT64 *gr30, UINT64 *gr31) { - - vmx_vcpu_get_gr(vcpu,29,gr29); - vmx_vcpu_get_gr(vcpu,30,gr30); - vmx_vcpu_get_gr(vcpu,31,gr31); -} - -static void -set_pal_result (VCPU *vcpu,struct ia64_pal_retval result) { - - vmx_vcpu_set_gr(vcpu,8, result.status,0); - vmx_vcpu_set_gr(vcpu,9, result.v0,0); - vmx_vcpu_set_gr(vcpu,10, result.v1,0); - vmx_vcpu_set_gr(vcpu,11, result.v2,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); - vmx_vcpu_get_gr(vcpu,28,&gr28); - - /* Always call Host Pal in int=1 */ - gr30 = gr30 &(~(0x2UL)); - - /* call Host PAL cache flush */ - result=ia64_pal_call_static(gr28 ,gr29, gr30,gr31,1); // Clear psr.ic when call PAL_CACHE_FLUSH - - /* 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); -// } - while (result.status != 0) { - panic("PAL_CACHE_FLUSH ERROR, status %d", result.status); - } - - return result; -} - -static struct ia64_pal_retval -pal_vm_tr_read (VCPU *vcpu ) { -#warning pal_vm_tr_read: to be implemented - struct ia64_pal_retval result; - - result.status= -1; //unimplemented - - 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; - - result.status= -1; //unimplemented - - return result; -} - -static struct ia64_pal_retval -pal_platform_addr(VCPU *vcpu) { - struct ia64_pal_retval result; - - result.status= 0; //success - - return result; -} - -static struct ia64_pal_retval -pal_halt (VCPU *vcpu) { -#warning pal_halt: to be implemented - //bugbug: to be implement. - struct ia64_pal_retval result; - - result.status= -1; //unimplemented - - return result; -} - - -static struct ia64_pal_retval -pal_halt_light (VCPU *vcpu) { - struct ia64_pal_retval result; - - result.status= -1; //unimplemented - - return result; -} - -static struct ia64_pal_retval -pal_cache_read (VCPU *vcpu) { - struct ia64_pal_retval result; - - result.status= -1; //unimplemented - - return result; -} - -static struct ia64_pal_retval -pal_cache_write (VCPU *vcpu) { - struct ia64_pal_retval result; - - result.status= -1; //unimplemented - - return result; -} - -static struct ia64_pal_retval -pal_bus_get_features(VCPU *vcpu){ - -} - -static struct ia64_pal_retval -pal_cache_summary(VCPU *vcpu){ - -} - -static struct ia64_pal_retval -pal_cache_init(VCPU *vcpu){ - struct ia64_pal_retval result; - result.status=0; - return result; -} - -static struct ia64_pal_retval -pal_cache_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_cache_prot_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_cache_shared_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_mem_attrib(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_debug_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_fixed_addr(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_freq_base(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_freq_ratios(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_halt_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_logical_to_physica(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_perf_mon_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_proc_get_features(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_ptce_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_register_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_rse_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_test_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_vm_summary(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_vm_info(VCPU *vcpu){ -} - -static struct ia64_pal_retval -pal_vm_page_size(VCPU *vcpu){ -} - -void -pal_emul( VCPU *vcpu) { - UINT64 gr28; - struct ia64_pal_retval result; - - - vmx_vcpu_get_gr(vcpu,28,&gr28); //bank1 - - 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; - - case PAL_CACHE_WRITE: - result = pal_cache_write (vcpu); - break; - - case PAL_PLATFORM_ADDR: - result = pal_platform_addr (vcpu); - break; - - default: - panic("pal_emul(): guest call unsupported pal" ); - } - set_pal_result (vcpu, result); -} - - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/pcdp.c --- a/xen/arch/ia64/pcdp.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,120 +0,0 @@ -/* - * Parse the EFI PCDP table to locate the console device. - * - * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P. - * Khalid Aziz <khalid.aziz@xxxxxx> - * Alex Williamson <alex.williamson@xxxxxx> - * Bjorn Helgaas <bjorn.helgaas@xxxxxx> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/acpi.h> -#include <linux/console.h> -#include <linux/efi.h> -#include <linux/serial.h> -#ifdef XEN -#include <linux/errno.h> -#endif -#include "pcdp.h" - -static int __init -setup_serial_console(struct pcdp_uart *uart) -{ -#ifdef XEN - extern struct ns16550_defaults ns16550_com1; - ns16550_com1.baud = uart->baud; - ns16550_com1.io_base = uart->addr.address; - if (uart->bits) - ns16550_com1.data_bits = uart->bits; - return 0; -#else -#ifdef CONFIG_SERIAL_8250_CONSOLE - int mmio; - static char options[64]; - - mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); - snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d", - mmio ? "mmio" : "io", uart->addr.address, uart->baud, - uart->bits ? uart->bits : 8); - - return early_serial_console_init(options); -#else - return -ENODEV; -#endif -#endif -} - -#ifndef XEN -static int __init -setup_vga_console(struct pcdp_vga *vga) -{ -#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) - if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) { - printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n"); - return -ENODEV; - } - - conswitchp = &vga_con; - printk(KERN_INFO "PCDP: VGA console\n"); - return 0; -#else - return -ENODEV; -#endif -} -#endif - -int __init -efi_setup_pcdp_console(char *cmdline) -{ - struct pcdp *pcdp; - struct pcdp_uart *uart; - struct pcdp_device *dev, *end; - int i, serial = 0; - - pcdp = efi.hcdp; - if (!pcdp) - return -ENODEV; - -#ifndef XEN - printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp)); -#endif - - if (strstr(cmdline, "console=hcdp")) { - if (pcdp->rev < 3) - serial = 1; - } else if (strstr(cmdline, "console=")) { -#ifndef XEN - printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n"); -#endif - return -ENODEV; - } - - if (pcdp->rev < 3 && efi_uart_console_only()) - serial = 1; - - for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { - if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { - if (uart->type == PCDP_CONSOLE_UART) { - return setup_serial_console(uart); - } - } - } - -#ifndef XEN - end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); - for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts); - dev < end; - dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { - if (dev->flags & PCDP_PRIMARY_CONSOLE) { - if (dev->type == PCDP_CONSOLE_VGA) { - return setup_vga_console((struct pcdp_vga *) dev); - } - } - } -#endif - - return -ENODEV; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/privop.c --- a/xen/arch/ia64/privop.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1130 +0,0 @@ -/* - * Privileged operation "API" handling functions. - * - * Copyright (C) 2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <asm/privop.h> -#include <asm/vcpu.h> -#include <asm/processor.h> -#include <asm/delay.h> // Debug only -//#include <debug.h> - -long priv_verbose=0; - -/************************************************************************** -Hypercall bundle creation -**************************************************************************/ - - -void build_hypercall_bundle(UINT64 *imva, UINT64 brkimm, UINT64 hypnum, UINT64 ret) -{ - INST64_A5 slot0; - INST64_I19 slot1; - INST64_B4 slot2; - IA64_BUNDLE bundle; - - // slot1: mov r2 = hypnum (low 20 bits) - slot0.inst = 0; - slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9; - slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7; - slot0.imm5c = hypnum >> 16; slot0.s = 0; - // slot1: break brkimm - slot1.inst = 0; - slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0; - slot1.imm20 = brkimm; slot1.i = brkimm >> 20; - // if ret slot2: br.ret.sptk.many rp - // else slot2: br.cond.sptk.many rp - slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0; - slot2.wh = 0; slot2.d = 0; slot2.major = 0x0; - if (ret) { - slot2.btype = 4; slot2.x6 = 0x21; - } - else { - slot2.btype = 0; slot2.x6 = 0x20; - } - - bundle.i64[0] = 0; bundle.i64[1] = 0; - bundle.template = 0x11; - bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst; - bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18; - - *imva++ = bundle.i64[0]; *imva = bundle.i64[1]; -} - -/************************************************************************** -Privileged operation emulation routines -**************************************************************************/ - -IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst) -{ - return vcpu_rfi(vcpu); -} - -IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst) -{ - return vcpu_bsw0(vcpu); -} - -IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst) -{ - return vcpu_bsw1(vcpu); -} - -IA64FAULT priv_cover(VCPU *vcpu, INST64 inst) -{ - return vcpu_cover(vcpu); -} - -IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst) -{ - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; - - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_l(vcpu,vadr,addr_range); -} - -IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst) -{ - UINT src = inst.M28.r3; - - // NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64) - if (src > 63) return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64))); - return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src)); -} - -IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst) -{ - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; - - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_g(vcpu,vadr,addr_range); -} - -IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst) -{ - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; - - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_ga(vcpu,vadr,addr_range); -} - -IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst) -{ - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; - - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptr_d(vcpu,vadr,addr_range); -} - -IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst) -{ - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; - - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptr_i(vcpu,vadr,addr_range); -} - -IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst) -{ - UINT64 padr; - UINT fault; - UINT src = inst.M46.r3; - - // NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64) - if (src > 63) - 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); - else return fault; -} - -IA64FAULT priv_tak(VCPU *vcpu, INST64 inst) -{ - UINT64 key; - UINT fault; - UINT src = inst.M46.r3; - - // NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64) - if (src > 63) - 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); - else return fault; -} - -/************************************ - * Insert translation register/cache -************************************/ - -IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst) -{ - UINT64 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); - - return (vcpu_itr_d(vcpu,slot,pte,itir,ifa)); -} - -IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst) -{ - UINT64 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); - - return (vcpu_itr_i(vcpu,slot,pte,itir,ifa)); -} - -IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst) -{ - UINT64 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); - - return (vcpu_itc_d(vcpu,pte,itir,ifa)); -} - -IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst) -{ - UINT64 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); - - return (vcpu_itc_i(vcpu,pte,itir,ifa)); -} - -/************************************* - * Moves to semi-privileged registers -*************************************/ - -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)); -} - -IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst) -{ - // I26 and M29 are identical for these fields - UINT64 ar3 = inst.M29.ar3; - - if (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); - else return IA64_ILLOP_FAULT; - } - else { - UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2); - return (vcpu_set_ar(vcpu,ar3,r2)); - } -} - -/******************************** - * Moves to privileged registers -********************************/ - -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)); -} - -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)); -} - -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)); -} - -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)); -} - -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)); -} - -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)); -} - -unsigned long to_cr_cnt[128] = { 0 }; - -IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst) -{ - UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2); - to_cr_cnt[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; - } -} - -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); -} - -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); -} - -/** - * @todo Check for reserved bits and return IA64_RSVDREG_FAULT. - */ -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); -} - -/********************************** - * Moves from privileged registers - **********************************/ - -IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - - if (inst.M43.r1 > 63) { // privified mov from cpuid - fault = vcpu_get_cpuid(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1-64, val); - } - else { - fault = vcpu_get_rr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1, val); - } - return fault; -} - -IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - - 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); - else return fault; -} - -IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - - 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); - else return fault; -} - -IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - - 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); - else return fault; -} - -IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - - if (inst.M43.r1 > 63) { // privified mov from pmd - fault = vcpu_get_pmd(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1-64, val); - } - else { - fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1, val); - } - return fault; -} - -unsigned long from_cr_cnt[128] = { 0 }; - -#define cr_get(cr) \ - ((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \ - vcpu_set_gr(vcpu, tgt, val) : fault; - -IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst) -{ - UINT64 tgt = inst.M33.r1; - UINT64 val; - IA64FAULT fault; - - from_cr_cnt[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); - 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; -} - -IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst) -{ - UINT64 tgt = inst.M33.r1; - UINT64 val; - IA64FAULT fault; - - if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, tgt, val); - else return fault; -} - -/************************************************************************** -Privileged operation decode and dispatch routines -**************************************************************************/ - -IA64_SLOT_TYPE slot_types[0x20][3] = { - {M, I, I}, {M, I, I}, {M, I, I}, {M, I, I}, - {M, I, ILLEGAL}, {M, I, ILLEGAL}, - {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, - {M, M, I}, {M, M, I}, {M, M, I}, {M, M, I}, - {M, F, I}, {M, F, I}, - {M, M, F}, {M, M, F}, - {M, I, B}, {M, I, B}, - {M, B, B}, {M, B, B}, - {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, - {B, B, B}, {B, B, B}, - {M, M, B}, {M, M, B}, - {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}, - {M, F, B}, {M, F, B}, - {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL} -}; - -// pointer to privileged emulation function -typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst); - -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 -}; - -struct { - unsigned long mov_to_ar_imm; - unsigned long mov_to_ar_reg; - unsigned long mov_from_ar; - unsigned long ssm; - unsigned long rsm; - unsigned long rfi; - unsigned long bsw0; - unsigned long bsw1; - unsigned long cover; - unsigned long fc; - unsigned long cpuid; - unsigned long Mpriv_cnt[64]; -} privcnt = { 0 }; - -unsigned long privop_trace = 0; - -IA64FAULT -priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) -{ - IA64_BUNDLE bundle; - IA64_BUNDLE __get_domain_bundle(UINT64); - int slot; - IA64_SLOT_TYPE slot_type; - INST64 inst; - PPEFCN pfunc; - unsigned long ipsr = regs->cr_ipsr; - UINT64 iip = regs->cr_iip; - int x6; - - // make a local copy of the bundle containing the privop -#if 1 - bundle = __get_domain_bundle(iip); - if (!bundle.i64[0] && !bundle.i64[1]) -#else - if (__copy_from_user(&bundle,iip,sizeof(bundle))) -#endif - { -//printf("*** priv_handle_op: privop bundle @%p not mapped, retrying\n",iip); - return vcpu_force_data_miss(vcpu,regs->cr_iip); - } -#if 0 - if (iip==0xa000000100001820) { - static int firstpagefault = 1; - if (firstpagefault) { - printf("*** First time to domain page fault!\n"); firstpagefault=0; - } - } -#endif - if (privop_trace) { - static long i = 400; - //if (i > 0) printf("privop @%p\n",iip); - if (i > 0) printf("priv_handle_op: @%p, 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; - 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); - - 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); - } - 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); - switch (slot_type) { - 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); - } -#endif - if (inst.M29.x3 != 0) break; - if (inst.M30.x4 == 8 && inst.M30.x2 == 2) { - privcnt.mov_to_ar_imm++; - return priv_mov_to_ar_imm(vcpu,inst); - } - if (inst.M44.x4 == 6) { - privcnt.ssm++; - return priv_ssm(vcpu,inst); - } - if (inst.M44.x4 == 7) { - privcnt.rsm++; - return priv_rsm(vcpu,inst); - } - break; - } - else if (inst.generic.major != 1) break; - x6 = inst.M29.x6; - if (x6 == 0x2a) { - if (inst.M29.r2 > 63 && inst.M29.ar3 < 8) - privcnt.mov_from_ar++; // privified mov from kr - else privcnt.mov_to_ar_reg++; - 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.M46.r3 > 63) { - if (x6 == 0x1e) x6 = 0x1b; - else x6 = 0x1a; - } - } - if (x6 == 52 && inst.M28.r3 > 63) - privcnt.fc++; - else if (x6 == 16 && inst.M43.r3 > 63) - privcnt.cpuid++; - else privcnt.Mpriv_cnt[x6]++; - return (*pfunc)(vcpu,inst); - break; - case B: - if (inst.generic.major != 0) break; - if (inst.B8.x6 == 0x08) { - IA64FAULT fault; - privcnt.rfi++; - fault = priv_rfi(vcpu,inst); - if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS; - return fault; - } - if (inst.B8.x6 == 0x0c) { - privcnt.bsw0++; - return priv_bsw0(vcpu,inst); - } - if (inst.B8.x6 == 0x0d) { - privcnt.bsw1++; - return priv_bsw1(vcpu,inst); - } - if (inst.B8.x6 == 0x0) { // break instr for privified cover - privcnt.cover++; - return priv_cover(vcpu,inst); - } - break; - case I: - if (inst.generic.major != 0) break; -#if 0 - if (inst.I26.x6 == 0 && inst.I26.x3 == 0) { - privcnt.cover++; - return priv_cover(vcpu,inst); - } -#endif - if (inst.I26.x3 != 0) break; // I26.x3 == I27.x3 - if (inst.I26.x6 == 0x2a) { - if (inst.I26.r2 > 63 && inst.I26.ar3 < 8) - privcnt.mov_from_ar++; // privified mov from kr - else privcnt.mov_to_ar_reg++; - return priv_mov_to_ar_reg(vcpu,inst); - } - if (inst.I27.x6 == 0x0a) { - privcnt.mov_to_ar_imm++; - return priv_mov_to_ar_imm(vcpu,inst); - } - break; - default: - break; - } - //printf("We who are about do die salute you\n"); - printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d), ipsr=%p\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); -} - -/** Emulate a privileged operation. - * - * This should probably return 0 on success and the "trap number" - * (e.g. illegal operation for bad register, priv op for an - * instruction that isn't allowed, etc.) on "failure" - * - * @param vcpu virtual cpu - * @param isrcode interrupt service routine code - * @return fault - */ -IA64FAULT -priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) -{ - IA64FAULT fault; - UINT64 ipsr = regs->cr_ipsr; - UINT64 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: returning ILLOP, not implemented!\n"); - while (1); - return IA64_ILLOP_FAULT; - } - //if (isrcode != 1 && isrcode != 2) return 0; - vcpu_set_regs(vcpu,regs); - privlvl = (ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT; - // 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!! - // 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=%p\n",isr); - return fault; -} - - -// FIXME: Move these to include/public/arch-ia64? -#define HYPERPRIVOP_RFI 0x1 -#define HYPERPRIVOP_RSM_DT 0x2 -#define HYPERPRIVOP_SSM_DT 0x3 -#define HYPERPRIVOP_COVER 0x4 -#define HYPERPRIVOP_ITC_D 0x5 -#define HYPERPRIVOP_ITC_I 0x6 -#define HYPERPRIVOP_SSM_I 0x7 -#define HYPERPRIVOP_GET_IVR 0x8 -#define HYPERPRIVOP_GET_TPR 0x9 -#define HYPERPRIVOP_SET_TPR 0xa -#define HYPERPRIVOP_EOI 0xb -#define HYPERPRIVOP_SET_ITM 0xc -#define HYPERPRIVOP_THASH 0xd -#define HYPERPRIVOP_PTC_GA 0xe -#define HYPERPRIVOP_ITR_D 0xf -#define HYPERPRIVOP_GET_RR 0x10 -#define HYPERPRIVOP_SET_RR 0x11 -#define HYPERPRIVOP_MAX 0x11 - -char *hyperpriv_str[HYPERPRIVOP_MAX+1] = { - 0, "rfi", "rsm.dt", "ssm.dt", "cover", "itc.d", "itc.i", "ssm.i", - "=ivr", "=tpr", "tpr=", "eoi", "itm=", "thash", "ptc.ga", "itr.d", - "=rr", "rr=", - 0 -}; - -unsigned long slow_hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; -unsigned long fast_hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; - -/* 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) -{ - struct vcpu *v = (struct domain *) current; - INST64 inst; - UINT64 val; - UINT64 itir, ifa; - -// FIXME: Handle faults appropriately for these - if (!iim || iim > HYPERPRIVOP_MAX) { - printf("bad hyperprivop; ignored\n"); - printf("iim=%d, iip=%p\n",iim,regs->cr_iip); - return 1; - } - slow_hyperpriv_cnt[iim]++; - switch(iim) { - case HYPERPRIVOP_RFI: - (void)vcpu_rfi(v); - return 0; // don't update iip - case HYPERPRIVOP_RSM_DT: - (void)vcpu_reset_psr_dt(v); - return 1; - case HYPERPRIVOP_SSM_DT: - (void)vcpu_set_psr_dt(v); - return 1; - case HYPERPRIVOP_COVER: - (void)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); - 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); - return 1; - case HYPERPRIVOP_SSM_I: - (void)vcpu_set_psr_i(v); - return 1; - case HYPERPRIVOP_GET_IVR: - (void)vcpu_get_ivr(v,&val); - regs->r8 = val; - return 1; - case HYPERPRIVOP_GET_TPR: - (void)vcpu_get_tpr(v,&val); - regs->r8 = val; - return 1; - case HYPERPRIVOP_SET_TPR: - (void)vcpu_set_tpr(v,regs->r8); - return 1; - case HYPERPRIVOP_EOI: - (void)vcpu_set_eoi(v,0L); - return 1; - case HYPERPRIVOP_SET_ITM: - (void)vcpu_set_itm(v,regs->r8); - return 1; - case HYPERPRIVOP_THASH: - (void)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))); - 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); - return 1; - case HYPERPRIVOP_GET_RR: - (void)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); - return 1; - } - return 0; -} - - -/************************************************************************** -Privileged operation instrumentation routines -**************************************************************************/ - -char *Mpriv_str[64] = { - "mov_to_rr", "mov_to_dbr", "mov_to_ibr", "mov_to_pkr", - "mov_to_pmc", "mov_to_pmd", "<0x06>", "<0x07>", - "<0x08>", "ptc_l", "ptc_g", "ptc_ga", - "ptr_d", "ptr_i", "itr_d", "itr_i", - "mov_from_rr", "mov_from_dbr", "mov_from_ibr", "mov_from_pkr", - "mov_from_pmc", "<0x15>", "<0x16>", "<0x17>", - "<0x18>", "<0x19>", "privified-thash", "privified-ttag", - "<0x1c>", "<0x1d>", "tpa", "tak", - "<0x20>", "<0x21>", "<0x22>", "<0x23>", - "mov_from_cr", "mov_from_psr", "<0x26>", "<0x27>", - "<0x28>", "<0x29>", "<0x2a>", "<0x2b>", - "mov_to_cr", "mov_to_psr", "itc_d", "itc_i", - "<0x30>", "<0x31>", "<0x32>", "<0x33>", - "ptc_e", "<0x35>", "<0x36>", "<0x37>", - "<0x38>", "<0x39>", "<0x3a>", "<0x3b>", - "<0x3c>", "<0x3d>", "<0x3e>", "<0x3f>" -}; - -#define RS "Rsvd" -char *cr_str[128] = { - "dcr","itm","iva",RS,RS,RS,RS,RS, - "pta",RS,RS,RS,RS,RS,RS,RS, - "ipsr","isr",RS,"iip","ifa","itir","iipa","ifs", - "iim","iha",RS,RS,RS,RS,RS,RS, - RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, - RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, - "lid","ivr","tpr","eoi","irr0","irr1","irr2","irr3", - "itv","pmv","cmcv",RS,RS,RS,RS,RS, - "lrr0","lrr1",RS,RS,RS,RS,RS,RS, - RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, - RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS, - RS,RS,RS,RS,RS,RS,RS,RS -}; - -// FIXME: should use snprintf to ensure no buffer overflow -int dump_privop_counts(char *buf) -{ - int i, j; - UINT64 sum = 0; - char *s = buf; - - // this is ugly and should probably produce sorted output - // but it will have to do for now - sum += privcnt.mov_to_ar_imm; sum += privcnt.mov_to_ar_reg; - sum += privcnt.ssm; sum += privcnt.rsm; - sum += privcnt.rfi; sum += privcnt.bsw0; - sum += privcnt.bsw1; sum += privcnt.cover; - for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i]; - s += sprintf(s,"Privop statistics: (Total privops: %ld)\n",sum); - if (privcnt.mov_to_ar_imm) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_imm, - "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum); - if (privcnt.mov_to_ar_reg) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_reg, - "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum); - if (privcnt.mov_from_ar) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_from_ar, - "privified-mov_from_ar", (privcnt.mov_from_ar*100L)/sum); - if (privcnt.ssm) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.ssm, - "ssm", (privcnt.ssm*100L)/sum); - if (privcnt.rsm) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rsm, - "rsm", (privcnt.rsm*100L)/sum); - if (privcnt.rfi) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rfi, - "rfi", (privcnt.rfi*100L)/sum); - if (privcnt.bsw0) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw0, - "bsw0", (privcnt.bsw0*100L)/sum); - if (privcnt.bsw1) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw1, - "bsw1", (privcnt.bsw1*100L)/sum); - if (privcnt.cover) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cover, - "cover", (privcnt.cover*100L)/sum); - if (privcnt.fc) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.fc, - "privified-fc", (privcnt.fc*100L)/sum); - if (privcnt.cpuid) - s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cpuid, - "privified-getcpuid", (privcnt.cpuid*100L)/sum); - for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) { - if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\n"); - else s += sprintf(s,"%10d %s [%d%%]\n", privcnt.Mpriv_cnt[i], - Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum); - if (i == 0x24) { // mov from CR - s += sprintf(s," ["); - for (j=0; j < 128; j++) if (from_cr_cnt[j]) { - if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\n"); - s += sprintf(s,"%s(%d),",cr_str[j],from_cr_cnt[j]); - } - s += sprintf(s,"]\n"); - } - else if (i == 0x2c) { // mov to CR - s += sprintf(s," ["); - for (j=0; j < 128; j++) if (to_cr_cnt[j]) { - if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\n"); - s += sprintf(s,"%s(%d),",cr_str[j],to_cr_cnt[j]); - } - s += sprintf(s,"]\n"); - } - } - return s - buf; -} - -int zero_privop_counts(char *buf) -{ - int i, j; - char *s = buf; - - // this is ugly and should probably produce sorted output - // but it will have to do for now - privcnt.mov_to_ar_imm = 0; privcnt.mov_to_ar_reg = 0; - privcnt.mov_from_ar = 0; - privcnt.ssm = 0; privcnt.rsm = 0; - privcnt.rfi = 0; privcnt.bsw0 = 0; - privcnt.bsw1 = 0; privcnt.cover = 0; - privcnt.fc = 0; privcnt.cpuid = 0; - for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0; - for (j=0; j < 128; j++) from_cr_cnt[j] = 0; - for (j=0; j < 128; j++) to_cr_cnt[j] = 0; - s += sprintf(s,"All privop statistics zeroed\n"); - return s - buf; -} - -#ifdef PRIVOP_ADDR_COUNT - -extern struct privop_addr_count privop_addr_counter[]; - -void privop_count_addr(unsigned long iip, int inst) -{ - struct privop_addr_count *v = &privop_addr_counter[inst]; - int i; - - for (i = 0; i < PRIVOP_COUNT_NADDRS; i++) { - if (!v->addr[i]) { v->addr[i] = iip; v->count[i]++; return; } - else if (v->addr[i] == iip) { v->count[i]++; return; } - } - v->overflow++;; -} - -int dump_privop_addrs(char *buf) -{ - int i,j; - char *s = buf; - s += sprintf(s,"Privop addresses:\n"); - for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { - struct privop_addr_count *v = &privop_addr_counter[i]; - s += sprintf(s,"%s:\n",v->instname); - for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) { - if (!v->addr[j]) break; - s += sprintf(s," @%p #%ld\n",v->addr[j],v->count[j]); - } - if (v->overflow) - s += sprintf(s," other #%ld\n",v->overflow); - } - return s - buf; -} - -void zero_privop_addrs(void) -{ - int i,j; - for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { - struct privop_addr_count *v = &privop_addr_counter[i]; - for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) - v->addr[j] = v->count[j] = 0; - v->overflow = 0; - } -} -#endif - -extern unsigned long dtlb_translate_count; -extern unsigned long tr_translate_count; -extern unsigned long phys_translate_count; -extern unsigned long vhpt_translate_count; -extern unsigned long lazy_cover_count; -extern unsigned long idle_when_pending; -extern unsigned long pal_halt_light_count; -extern unsigned long context_switch_count; - -int dump_misc_stats(char *buf) -{ - char *s = buf; - s += sprintf(s,"Virtual TR translations: %d\n",tr_translate_count); - s += sprintf(s,"Virtual VHPT translations: %d\n",vhpt_translate_count); - s += sprintf(s,"Virtual DTLB translations: %d\n",dtlb_translate_count); - s += sprintf(s,"Physical translations: %d\n",phys_translate_count); - s += sprintf(s,"Idle when pending: %d\n",idle_when_pending); - s += sprintf(s,"PAL_HALT_LIGHT (no pending): %d\n",pal_halt_light_count); - s += sprintf(s,"context switches: %d\n",context_switch_count); - s += sprintf(s,"Lazy covers: %d\n",lazy_cover_count); - return s - buf; -} - -void zero_misc_stats(void) -{ - dtlb_translate_count = 0; - tr_translate_count = 0; - phys_translate_count = 0; - vhpt_translate_count = 0; - lazy_cover_count = 0; - pal_halt_light_count = 0; - idle_when_pending = 0; - context_switch_count = 0; -} - -int dump_hyperprivop_counts(char *buf) -{ - int i; - char *s = buf; - unsigned long total = 0; - for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += slow_hyperpriv_cnt[i]; - s += sprintf(s,"Slow hyperprivops (total %d):\n",total); - for (i = 1; i <= HYPERPRIVOP_MAX; i++) - if (slow_hyperpriv_cnt[i]) - s += sprintf(s,"%10d %s\n", - slow_hyperpriv_cnt[i], hyperpriv_str[i]); - total = 0; - for (i = 1; i <= HYPERPRIVOP_MAX; i++) total += fast_hyperpriv_cnt[i]; - s += sprintf(s,"Fast hyperprivops (total %d):\n",total); - for (i = 1; i <= HYPERPRIVOP_MAX; i++) - if (fast_hyperpriv_cnt[i]) - s += sprintf(s,"%10d %s\n", - fast_hyperpriv_cnt[i], hyperpriv_str[i]); - return s - buf; -} - -void zero_hyperprivop_counts(void) -{ - int i; - for (i = 0; i <= HYPERPRIVOP_MAX; i++) slow_hyperpriv_cnt[i] = 0; - for (i = 0; i <= HYPERPRIVOP_MAX; i++) fast_hyperpriv_cnt[i] = 0; -} - -#define TMPBUFLEN 8*1024 -int dump_privop_counts_to_user(char __user *ubuf, int len) -{ - char buf[TMPBUFLEN]; - int n = dump_privop_counts(buf); - - n += dump_hyperprivop_counts(buf + n); - n += dump_reflect_counts(buf + n); -#ifdef PRIVOP_ADDR_COUNT - n += dump_privop_addrs(buf + n); -#endif - n += dump_misc_stats(buf + n); - if (len < TMPBUFLEN) return -1; - if (__copy_to_user(ubuf,buf,n)) return -1; - return n; -} - -int zero_privop_counts_to_user(char __user *ubuf, int len) -{ - char buf[TMPBUFLEN]; - int n = zero_privop_counts(buf); - - zero_hyperprivop_counts(); -#ifdef PRIVOP_ADDR_COUNT - zero_privop_addrs(); -#endif - zero_misc_stats(); - zero_reflect_counts(); - if (len < TMPBUFLEN) return -1; - if (__copy_to_user(ubuf,buf,n)) return -1; - return n; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/process.c --- a/xen/arch/ia64/process.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,749 +0,0 @@ -/* - * Miscellaneous process/domain related routines - * - * Copyright (C) 2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/errno.h> -#include <xen/sched.h> -#include <xen/smp.h> -#include <asm/ptrace.h> -#include <xen/delay.h> - -#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ -#include <asm/sal.h> /* FOR struct ia64_sal_retval */ - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/desc.h> -//#include <asm/ldt.h> -#include <xen/irq.h> -#include <xen/event.h> -#include <asm/regionreg.h> -#include <asm/privop.h> -#include <asm/vcpu.h> -#include <asm/ia64_int.h> -#include <asm/dom_fw.h> -#include "hpsim_ssc.h" - -extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); -extern struct ia64_sal_retval pal_emulator_static(UINT64); -extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); - -extern unsigned long dom0_start, dom0_size; - -#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT) -// note IA64_PSR_PK removed from following, why is this necessary? -#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \ - IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \ - IA64_PSR_IT | IA64_PSR_BN) - -#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \ - IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \ - IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \ - IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \ - IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ - IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) - -#define PSCB(x,y) VCPU(x,y) -#define PSCBX(x,y) x->arch.y - -extern unsigned long vcpu_verbose; - -long do_iopl(domid_t domain, unsigned int new_io_pl) -{ - dummy(); - return 0; -} - -void schedule_tail(struct vcpu *next) -{ - unsigned long rr7; - //printk("current=%lx,shared_info=%lx\n",current,current->vcpu_info); - //printk("next=%lx,shared_info=%lx\n",next,next->vcpu_info); -#ifdef CONFIG_VTI - /* rr7 will be postponed to last point when resuming back to guest */ - vmx_load_all_rr(current); -#else // CONFIG_VTI - if (rr7 = load_region_regs(current)) { - printk("schedule_tail: change to rr7 not yet implemented\n"); - } -#endif // CONFIG_VTI -} - -void tdpfoo(void) { } - -// given a domain virtual address, pte and pagesize, extract the metaphysical -// address, convert the pte for a physical address for (possibly different) -// Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use -// PAGE_SIZE!) -unsigned long translate_domain_pte(unsigned long pteval, - unsigned long address, unsigned long itir) -{ - struct domain *d = current->domain; - unsigned long mask, pteval2, mpaddr; - unsigned long lookup_domain_mpa(struct domain *,unsigned long); - extern struct domain *dom0; - extern unsigned long dom0_start, dom0_size; - - // FIXME address had better be pre-validated on insert - mask = (1L << ((itir >> 2) & 0x3f)) - 1; - mpaddr = ((pteval & _PAGE_PPN_MASK) & ~mask) | (address & mask); - if (d == dom0) { - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - //printk("translate_domain_pte: out-of-bounds dom0 mpaddr %p! itc=%lx...\n",mpaddr,ia64_get_itc()); - tdpfoo(); - } - } - else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) { - printf("translate_domain_pte: bad mpa=%p (> %p),vadr=%p,pteval=%p,itir=%p\n", - mpaddr,d->max_pages<<PAGE_SHIFT,address,pteval,itir); - tdpfoo(); - } - pteval2 = lookup_domain_mpa(d,mpaddr); - pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits - pteval2 |= _PAGE_PL_2; // force PL0->2 (PL3 is unaffected) - pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2; - return pteval2; -} - -// given a current domain metaphysical address, return the physical address -unsigned long translate_domain_mpaddr(unsigned long mpaddr) -{ - extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); - unsigned long pteval; - - if (current->domain == dom0) { - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr); - tdpfoo(); - } - } - pteval = lookup_domain_mpa(current->domain,mpaddr); - return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK)); -} - -unsigned long slow_reflect_count[0x80] = { 0 }; -unsigned long fast_reflect_count[0x80] = { 0 }; - -#define inc_slow_reflect_count(vec) slow_reflect_count[vec>>8]++; - -void zero_reflect_counts(void) -{ - int i; - for (i=0; i<0x80; i++) slow_reflect_count[i] = 0; - for (i=0; i<0x80; i++) fast_reflect_count[i] = 0; -} - -int dump_reflect_counts(char *buf) -{ - int i,j,cnt; - char *s = buf; - - s += sprintf(s,"Slow reflections by vector:\n"); - for (i = 0, j = 0; i < 0x80; i++) { - if (cnt = slow_reflect_count[i]) { - s += sprintf(s,"0x%02x00:%10d, ",i,cnt); - if ((j++ & 3) == 3) s += sprintf(s,"\n"); - } - } - if (j & 3) s += sprintf(s,"\n"); - s += sprintf(s,"Fast reflections by vector:\n"); - for (i = 0, j = 0; i < 0x80; i++) { - if (cnt = fast_reflect_count[i]) { - s += sprintf(s,"0x%02x00:%10d, ",i,cnt); - if ((j++ & 3) == 3) s += sprintf(s,"\n"); - } - } - if (j & 3) s += sprintf(s,"\n"); - return s - buf; -} - -void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector) -{ - unsigned long vcpu_get_ipsr_int_state(struct vcpu *,unsigned long); - unsigned long vcpu_get_rr_ve(struct vcpu *,unsigned long); - struct domain *d = current->domain; - struct vcpu *v = current; - - if (vector == IA64_EXTINT_VECTOR) { - - extern unsigned long vcpu_verbose, privop_trace; - static first_extint = 1; - if (first_extint) { - printf("Delivering first extint to domain: ifa=%p, isr=%p, itir=%p, iip=%p\n",ifa,isr,itiriim,regs->cr_iip); - //privop_trace = 1; vcpu_verbose = 1; - first_extint = 0; - } - } - if (!PSCB(v,interrupt_collection_enabled)) { - if (!(PSCB(v,ipsr) & IA64_PSR_DT)) { - panic_domain(regs,"psr.dt off, trying to deliver nested dtlb!\n"); - } - vector &= ~0xf; - if (vector != IA64_DATA_TLB_VECTOR && - vector != IA64_ALT_DATA_TLB_VECTOR && - vector != IA64_VHPT_TRANS_VECTOR) { -panic_domain(regs,"psr.ic off, delivering fault=%lx,ipsr=%p,iip=%p,ifa=%p,isr=%p,PSCB.iip=%p\n", - vector,regs->cr_ipsr,regs->cr_iip,ifa,isr,PSCB(v,iip)); - - } -//printf("Delivering NESTED DATA TLB fault\n"); - vector = IA64_DATA_NESTED_TLB_VECTOR; - regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL; - regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; -// NOTE: nested trap must NOT pass PSCB address - //regs->r31 = (unsigned long) &PSCB(v); - inc_slow_reflect_count(vector); - return; - - } - if ((vector & 0xf) == IA64_FORCED_IFA) - ifa = PSCB(v,tmp[0]); - vector &= ~0xf; - PSCB(v,ifa) = ifa; - if (vector < IA64_DATA_NESTED_TLB_VECTOR) /* VHPT miss, TLB miss, Alt TLB miss */ - vcpu_thash(v,ifa,&PSCB(current,iha)); - PSCB(v,unat) = regs->ar_unat; // not sure if this is really needed? - PSCB(v,precover_ifs) = regs->cr_ifs; - vcpu_bsw0(v); - PSCB(v,ipsr) = vcpu_get_ipsr_int_state(v,regs->cr_ipsr); - if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) - PSCB(v,iim) = itiriim; - else PSCB(v,itir) = vcpu_get_itir_on_fault(v,ifa); - PSCB(v,isr) = isr; // this is unnecessary except for interrupts! - PSCB(v,iip) = regs->cr_iip; - PSCB(v,ifs) = 0; - PSCB(v,incomplete_regframe) = 0; - - regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL; - regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; -#ifdef CONFIG_SMP -#warning "SMP FIXME: sharedinfo doesn't handle smp yet, need page per vcpu" -#endif - regs->r31 = &(((mapped_regs_t *)SHARED_ARCHINFO_ADDR)->ipsr); - - PSCB(v,interrupt_delivery_enabled) = 0; - PSCB(v,interrupt_collection_enabled) = 0; - - inc_slow_reflect_count(vector); -} - -void foodpi(void) {} - -unsigned long pending_false_positive = 0; - -// ONLY gets called from ia64_leave_kernel -// ONLY call with interrupts disabled?? (else might miss one?) -// NEVER successful if already reflecting a trap/fault because psr.i==0 -void deliver_pending_interrupt(struct pt_regs *regs) -{ - struct domain *d = current->domain; - struct vcpu *v = current; - // FIXME: Will this work properly if doing an RFI??? - if (!is_idle_task(d) && user_mode(regs)) { - //vcpu_poke_timer(v); - if (vcpu_deliverable_interrupts(v)) { - unsigned long isr = regs->cr_ipsr & IA64_PSR_RI; - if (vcpu_timer_pending_early(v)) -printf("*#*#*#* about to deliver early timer to domain %d!!!\n",v->domain->domain_id); - reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR); - } - else if (PSCB(v,pending_interruption)) - ++pending_false_positive; - } -} -unsigned long lazy_cover_count = 0; - -int handle_lazy_cover(struct vcpu *v, unsigned long isr, struct pt_regs *regs) -{ - if (!PSCB(v,interrupt_collection_enabled)) { - PSCB(v,ifs) = regs->cr_ifs; - PSCB(v,incomplete_regframe) = 1; - regs->cr_ifs = 0; - lazy_cover_count++; - return(1); // retry same instruction with cr.ifs off - } - return(0); -} - -void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir) -{ - unsigned long iip = regs->cr_iip; - // FIXME should validate address here - unsigned long pteval; - unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL); - IA64FAULT fault; - - if ((isr & IA64_ISR_IR) && handle_lazy_cover(current, isr, regs)) return; - if ((isr & IA64_ISR_SP) - || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) - { - /* - * This fault was due to a speculative load or lfetch.fault, set the "ed" - * bit in the psr to ensure forward progress. (Target register will get a - * NaT for ld.s, lfetch will be canceled.) - */ - ia64_psr(regs)->ed = 1; - return; - } - - fault = vcpu_translate(current,address,is_data,&pteval,&itir); - if (fault == IA64_NO_FAULT) - { - pteval = translate_domain_pte(pteval,address,itir); - vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,(itir>>2)&0x3f); - return; - } - else if (IS_VMM_ADDRESS(iip)) - { - if (!ia64_done_with_exception(regs)) { - // should never happen. If it does, region 0 addr may - // indicate a bad xen pointer - printk("*** xen_handle_domain_access: exception table" - " lookup failed, iip=%p, addr=%p, spinning...\n", - iip,address); - panic_domain(regs,"*** xen_handle_domain_access: exception table" - " lookup failed, iip=%p, addr=%p, spinning...\n", - iip,address); - } - return; - } - - reflect_interruption(address, isr, 0, regs, fault); -} - -void -ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, - unsigned long iim, unsigned long itir, unsigned long arg5, - unsigned long arg6, unsigned long arg7, unsigned long stack) -{ - struct pt_regs *regs = (struct pt_regs *) &stack; - unsigned long code, error = isr; - char buf[128]; - int result, sig; - static const char *reason[] = { - "IA-64 Illegal Operation fault", - "IA-64 Privileged Operation fault", - "IA-64 Privileged Register fault", - "IA-64 Reserved Register/Field fault", - "Disabled Instruction Set Transition fault", - "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", - "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", - "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" - }; -#if 0 -printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", - vector, ifa, regs->cr_iip, regs->cr_ipsr, isr); -#endif - - if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { - /* - * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel - * the lfetch. - */ - ia64_psr(regs)->ed = 1; - printf("ia64_fault: handled lfetch.fault\n"); - return; - } - - switch (vector) { - case 24: /* General Exception */ - code = (isr >> 4) & 0xf; - sprintf(buf, "General Exception: %s%s", reason[code], - (code == 3) ? ((isr & (1UL << 37)) - ? " (RSE access)" : " (data access)") : ""); - if (code == 8) { -# ifdef CONFIG_IA64_PRINT_HAZARDS - printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n", - current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, - regs->pr); -# endif - printf("ia64_fault: returning on hazard\n"); - return; - } - break; - - case 25: /* Disabled FP-Register */ - if (isr & 2) { - //disabled_fph_fault(regs); - //return; - } - sprintf(buf, "Disabled FPL fault---not supposed to happen!"); - break; - - case 26: /* NaT Consumption */ - if (user_mode(regs)) { - void *addr; - - if (((isr >> 4) & 0xf) == 2) { - /* NaT page consumption */ - //sig = SIGSEGV; - //code = SEGV_ACCERR; - addr = (void *) ifa; - } else { - /* register NaT consumption */ - //sig = SIGILL; - //code = ILL_ILLOPN; - addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - } - //siginfo.si_signo = sig; - //siginfo.si_code = code; - //siginfo.si_errno = 0; - //siginfo.si_addr = addr; - //siginfo.si_imm = vector; - //siginfo.si_flags = __ISR_VALID; - //siginfo.si_isr = isr; - //force_sig_info(sig, &siginfo, current); - //return; - } //else if (ia64_done_with_exception(regs)) - //return; - sprintf(buf, "NaT consumption"); - break; - - case 31: /* Unsupported Data Reference */ - if (user_mode(regs)) { - //siginfo.si_signo = SIGILL; - //siginfo.si_code = ILL_ILLOPN; - //siginfo.si_errno = 0; - //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - //siginfo.si_imm = vector; - //siginfo.si_flags = __ISR_VALID; - //siginfo.si_isr = isr; - //force_sig_info(SIGILL, &siginfo, current); - //return; - } - sprintf(buf, "Unsupported data reference"); - break; - - case 29: /* Debug */ - case 35: /* Taken Branch Trap */ - case 36: /* Single Step Trap */ - //if (fsys_mode(current, regs)) {} - switch (vector) { - case 29: - //siginfo.si_code = TRAP_HWBKPT; -#ifdef CONFIG_ITANIUM - /* - * Erratum 10 (IFA may contain incorrect address) now has - * "NoFix" status. There are no plans for fixing this. - */ - if (ia64_psr(regs)->is == 0) - ifa = regs->cr_iip; -#endif - break; - case 35: ifa = 0; break; - case 36: ifa = 0; break; - //case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; - //case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; - } - //siginfo.si_signo = SIGTRAP; - //siginfo.si_errno = 0; - //siginfo.si_addr = (void *) ifa; - //siginfo.si_imm = 0; - //siginfo.si_flags = __ISR_VALID; - //siginfo.si_isr = isr; - //force_sig_info(SIGTRAP, &siginfo, current); - //return; - - case 32: /* fp fault */ - case 33: /* fp trap */ - //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); - //if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { - //siginfo.si_signo = SIGFPE; - //siginfo.si_errno = 0; - //siginfo.si_code = FPE_FLTINV; - //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - //siginfo.si_flags = __ISR_VALID; - //siginfo.si_isr = isr; - //siginfo.si_imm = 0; - //force_sig_info(SIGFPE, &siginfo, current); - //} - //return; - sprintf(buf, "FP fault/trap"); - break; - - case 34: - if (isr & 0x2) { - /* Lower-Privilege Transfer Trap */ - /* - * Just clear PSR.lp and then return immediately: all the - * interesting work (e.g., signal delivery is done in the kernel - * exit path). - */ - //ia64_psr(regs)->lp = 0; - //return; - sprintf(buf, "Lower-Privilege Transfer trap"); - } else { - /* Unimplemented Instr. Address Trap */ - if (user_mode(regs)) { - //siginfo.si_signo = SIGILL; - //siginfo.si_code = ILL_BADIADDR; - //siginfo.si_errno = 0; - //siginfo.si_flags = 0; - //siginfo.si_isr = 0; - //siginfo.si_imm = 0; - //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - //force_sig_info(SIGILL, &siginfo, current); - //return; - } - sprintf(buf, "Unimplemented Instruction Address fault"); - } - break; - - case 45: - printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n"); - printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", - regs->cr_iip, ifa, isr); - //force_sig(SIGSEGV, current); - break; - - case 46: - printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n"); - printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", - regs->cr_iip, ifa, isr, iim); - //force_sig(SIGSEGV, current); - return; - - case 47: - sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); - break; - - default: - sprintf(buf, "Fault %lu", vector); - break; - } - //die_if_kernel(buf, regs, error); -printk("ia64_fault: %s: reflecting\n",buf); -reflect_interruption(ifa,isr,iim,regs,IA64_GENEX_VECTOR); -//while(1); - //force_sig(SIGILL, current); -} - -unsigned long running_on_sim = 0; - -void -do_ssc(unsigned long ssc, struct pt_regs *regs) -{ - extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); - unsigned long arg0, arg1, arg2, arg3, retval; - char buf[2]; -/**/ static int last_fd, last_count; // FIXME FIXME FIXME -/**/ // BROKEN FOR MULTIPLE DOMAINS & SMP -/**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat; - extern unsigned long vcpu_verbose, privop_trace; - - arg0 = vcpu_get_gr(current,32); - switch(ssc) { - case SSC_PUTCHAR: - buf[0] = arg0; - buf[1] = '\0'; - printf(buf); - break; - case SSC_GETCHAR: - retval = ia64_ssc(0,0,0,0,ssc); - vcpu_set_gr(current,8,retval); - break; - case SSC_WAIT_COMPLETION: - if (arg0) { // metaphysical address - - arg0 = translate_domain_mpaddr(arg0); -/**/ stat = (struct ssc_disk_stat *)__va(arg0); -///**/ if (stat->fd == last_fd) stat->count = last_count; -/**/ stat->count = last_count; -//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count); -///**/ retval = ia64_ssc(arg0,0,0,0,ssc); -/**/ retval = 0; - } - else retval = -1L; - vcpu_set_gr(current,8,retval); - break; - case SSC_OPEN: - arg1 = vcpu_get_gr(current,33); // access rights -if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; } - if (arg0) { // metaphysical address - arg0 = translate_domain_mpaddr(arg0); - retval = ia64_ssc(arg0,arg1,0,0,ssc); - } - else retval = -1L; - vcpu_set_gr(current,8,retval); - break; - case SSC_WRITE: - case SSC_READ: -//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n"); - arg1 = vcpu_get_gr(current,33); - arg2 = vcpu_get_gr(current,34); - arg3 = vcpu_get_gr(current,35); - if (arg2) { // metaphysical address of descriptor - struct ssc_disk_req *req; - unsigned long mpaddr, paddr; - long len; - - arg2 = translate_domain_mpaddr(arg2); - req = (struct disk_req *)__va(arg2); - req->len &= 0xffffffffL; // avoid strange bug - len = req->len; -/**/ last_fd = arg1; -/**/ last_count = len; - mpaddr = req->addr; -//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len); - retval = 0; - if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) { - // do partial page first - req->addr = translate_domain_mpaddr(mpaddr); - req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK); - len -= req->len; mpaddr += req->len; - retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); - arg3 += req->len; // file offset -/**/ last_stat.fd = last_fd; -/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); -//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval); - } - if (retval >= 0) while (len > 0) { - req->addr = translate_domain_mpaddr(mpaddr); - req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len; - len -= PAGE_SIZE; mpaddr += PAGE_SIZE; - retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); - arg3 += req->len; // file offset -// TEMP REMOVED AGAIN arg3 += req->len; // file offset -/**/ last_stat.fd = last_fd; -/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); -//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval); - } - // set it back to the original value - req->len = last_count; - } - else retval = -1L; - vcpu_set_gr(current,8,retval); -//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval); - break; - case SSC_CONNECT_INTERRUPT: - arg1 = vcpu_get_gr(current,33); - arg2 = vcpu_get_gr(current,34); - arg3 = vcpu_get_gr(current,35); - if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; } - (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc); - break; - case SSC_NETDEV_PROBE: - vcpu_set_gr(current,8,-1L); - break; - default: - printf("ia64_handle_break: bad ssc code %lx, iip=%p, b0=%p... spinning\n",ssc,regs->cr_iip,regs->b0); - while(1); - break; - } - vcpu_increment_iip(current); -} - -int first_break = 1; - -void -ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) -{ - struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; - extern unsigned long running_on_sim; - - if (first_break) { - if (platform_is_hp_ski()) running_on_sim = 1; - else running_on_sim = 0; - first_break = 0; - } - if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant - if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); - else do_ssc(vcpu_get_gr(current,36), regs); - } - else if (iim == d->arch.breakimm) { - if (ia64_hypercall(regs)) - vcpu_increment_iip(current); - } - else if (!PSCB(v,interrupt_collection_enabled)) { - if (ia64_hyperprivop(iim,regs)) - vcpu_increment_iip(current); - } - else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR); -} - -void -ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir) -{ - IA64FAULT vector; - struct domain *d = current->domain; - struct vcpu *v = current; - // FIXME: no need to pass itir in to this routine as we need to - // compute the virtual itir anyway (based on domain's RR.ps) - // AND ACTUALLY reflect_interruption doesn't use it anyway! - itir = vcpu_get_itir_on_fault(v,ifa); - vector = priv_emulate(current,regs,isr); - if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) { - reflect_interruption(ifa,isr,itir,regs,vector); - } -} - -#define INTR_TYPE_MAX 10 -UINT64 int_counts[INTR_TYPE_MAX]; - -void -ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector) -{ - struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; - unsigned long check_lazy_cover = 0; - unsigned long psr = regs->cr_ipsr; - unsigned long itir = vcpu_get_itir_on_fault(v,ifa); - - if (!(psr & IA64_PSR_CPL)) { - printk("ia64_handle_reflection: reflecting with priv=0!!\n"); - } - // FIXME: no need to pass itir in to this routine as we need to - // compute the virtual itir anyway (based on domain's RR.ps) - // AND ACTUALLY reflect_interruption doesn't use it anyway! - itir = vcpu_get_itir_on_fault(v,ifa); - switch(vector) { - case 8: - vector = IA64_DIRTY_BIT_VECTOR; break; - case 9: - vector = IA64_INST_ACCESS_BIT_VECTOR; break; - case 10: - check_lazy_cover = 1; - vector = IA64_DATA_ACCESS_BIT_VECTOR; break; - case 20: - check_lazy_cover = 1; - vector = IA64_PAGE_NOT_PRESENT_VECTOR; break; - case 22: - vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break; - case 23: - check_lazy_cover = 1; - vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break; - case 25: - vector = IA64_DISABLED_FPREG_VECTOR; - break; - case 26: -printf("*** NaT fault... attempting to handle as privop\n"); -printf("isr=%p, ifa=%p,iip=%p,ipsr=%p\n",isr,ifa,regs->cr_iip,psr); - vector = priv_emulate(v,regs,isr); - if (vector == IA64_NO_FAULT) { -printf("*** Handled privop masquerading as NaT fault\n"); - return; - } - vector = IA64_NAT_CONSUMPTION_VECTOR; break; - case 27: -//printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc()); - itir = iim; - vector = IA64_SPECULATION_VECTOR; break; - case 30: - // FIXME: Should we handle unaligned refs in Xen?? - vector = IA64_UNALIGNED_REF_VECTOR; break; - default: - printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector); - while(vector); - return; - } - if (check_lazy_cover && (isr & IA64_ISR_IR) && handle_lazy_cover(v, isr, regs)) return; - reflect_interruption(ifa,isr,itir,regs,vector); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/regionreg.c --- a/xen/arch/ia64/regionreg.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,376 +0,0 @@ -/* - * Region register and region id management - * - * Copyright (C) 2001-2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx - * Bret Mckee (bret.mckee@xxxxxx) - * - */ - - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <asm/page.h> -#include <asm/regionreg.h> -#include <asm/vhpt.h> -#include <asm/vcpu.h> -extern void ia64_new_rr7(unsigned long rid,void *shared_info, void *shared_arch_info); - - -#define IA64_MIN_IMPL_RID_BITS (IA64_MIN_IMPL_RID_MSB+1) -#define IA64_MAX_IMPL_RID_BITS 24 - -#define MIN_RIDS (1 << IA64_MIN_IMPL_RID_BITS) -#define MIN_RID_MAX (MIN_RIDS - 1) -#define MIN_RID_MASK (MIN_RIDS - 1) -#define MAX_RIDS (1 << (IA64_MAX_IMPL_RID_BITS)) -#define MAX_RID (MAX_RIDS - 1) -#define MAX_RID_BLOCKS (1 << (IA64_MAX_IMPL_RID_BITS-IA64_MIN_IMPL_RID_BITS)) -#define RIDS_PER_RIDBLOCK MIN_RIDS - -#if 0 -// following already defined in include/asm-ia64/gcc_intrin.h -// it should probably be ifdef'd out from there to ensure all region -// register usage is encapsulated in this file -static inline unsigned long -ia64_get_rr (unsigned long rr) -{ - unsigned long r; - __asm__ __volatile__ (";;mov %0=rr[%1];;":"=r"(r):"r"(rr):"memory"); - return r; -} - -static inline void -ia64_set_rr (unsigned long rr, unsigned long rrv) -{ - __asm__ __volatile__ (";;mov rr[%0]=%1;;"::"r"(rr),"r"(rrv):"memory"); -} -#endif - -// use this to allocate a rid out of the "Xen reserved rid block" -unsigned long allocate_reserved_rid(void) -{ - static unsigned long currentrid = XEN_DEFAULT_RID; - unsigned long t = currentrid; - - unsigned long max = RIDS_PER_RIDBLOCK; - - if (++currentrid >= max) return(-1UL); - return t; -} - - -// returns -1 if none available -unsigned long allocate_metaphysical_rr(void) -{ - ia64_rr rrv; - - rrv.rid = allocate_reserved_rid(); - rrv.ps = PAGE_SHIFT; - rrv.ve = 0; - return rrv.rrval; -} - -int deallocate_metaphysical_rid(unsigned long rid) -{ - // fix this when the increment allocation mechanism is fixed. - return 1; -} - -/************************************* - Region Block setup/management -*************************************/ - -static int implemented_rid_bits = 0; -static struct domain *ridblock_owner[MAX_RID_BLOCKS] = { 0 }; - -void get_impl_rid_bits(void) -{ - // FIXME (call PAL) -//#ifdef CONFIG_MCKINLEY - implemented_rid_bits = IA64_MAX_IMPL_RID_BITS; -//#else -//#error "rid ranges won't work on Merced" -//#endif - if (implemented_rid_bits <= IA64_MIN_IMPL_RID_BITS || - implemented_rid_bits > IA64_MAX_IMPL_RID_BITS) - BUG(); -} - - -/* - * Allocate a power-of-two-sized chunk of region id space -- one or more - * "rid blocks" - */ -int allocate_rid_range(struct domain *d, unsigned long ridbits) -{ - int i, j, n_rid_blocks; - - if (implemented_rid_bits == 0) get_impl_rid_bits(); - - if (ridbits >= IA64_MAX_IMPL_RID_BITS) - ridbits = IA64_MAX_IMPL_RID_BITS - 1; - - if (ridbits < IA64_MIN_IMPL_RID_BITS) - ridbits = IA64_MIN_IMPL_RID_BITS; - - // convert to rid_blocks and find one - n_rid_blocks = ridbits - IA64_MIN_IMPL_RID_BITS + 1; - - // skip over block 0, reserved for "meta-physical mappings (and Xen)" - for (i = n_rid_blocks; i < MAX_RID_BLOCKS; i += n_rid_blocks) { - if (ridblock_owner[i] == NULL) { - for (j = i; j < i + n_rid_blocks; ++j) { - if (ridblock_owner[j]) break; - } - if (ridblock_owner[j] == NULL) break; - } - } - - if (i >= MAX_RID_BLOCKS) return 0; - - // found an unused block: - // (i << min_rid_bits) <= rid < ((i + n) << min_rid_bits) - // mark this block as owned - for (j = i; j < i + n_rid_blocks; ++j) ridblock_owner[j] = d; - - // setup domain struct - d->arch.rid_bits = ridbits; - d->arch.starting_rid = i << IA64_MIN_IMPL_RID_BITS; d->arch.ending_rid = (i+n_rid_blocks) << IA64_MIN_IMPL_RID_BITS; -printf("###allocating rid_range, domain %p: starting_rid=%lx, ending_rid=%lx\n", -d,d->arch.starting_rid, d->arch.ending_rid); - - return 1; -} - - -int deallocate_rid_range(struct domain *d) -{ - int i; - int rid_block_end = d->arch.ending_rid >> IA64_MIN_IMPL_RID_BITS; - int rid_block_start = d->arch.starting_rid >> IA64_MIN_IMPL_RID_BITS; - - return 1; // KLUDGE ALERT - // - // not all domains will have allocated RIDs (physical mode loaders for instance) - // - if (d->arch.rid_bits == 0) return 1; - -#ifdef DEBUG - for (i = rid_block_start; i < rid_block_end; ++i) { - ASSERT(ridblock_owner[i] == d); - } -#endif - - for (i = rid_block_start; i < rid_block_end; ++i) - ridblock_owner[i] = NULL; - - d->arch.rid_bits = 0; - d->arch.starting_rid = 0; - d->arch.ending_rid = 0; - return 1; -} - - -static inline void -set_rr_no_srlz(unsigned long rr, unsigned long rrval) -{ - ia64_set_rr(rr, vmMangleRID(rrval)); -} - -void -set_rr(unsigned long rr, unsigned long rrval) -{ - ia64_set_rr(rr, vmMangleRID(rrval)); - ia64_srlz_d(); -} - -unsigned long -get_rr(unsigned long rr) -{ - return vmUnmangleRID(ia64_get_rr(rr)); -} - -static inline int validate_page_size(unsigned long ps) -{ - switch(ps) { - case 12: case 13: case 14: case 16: case 18: - case 20: case 22: case 24: case 26: case 28: - return 1; - default: - return 0; - } -} - -// validates and changes a single region register -// in the currently executing domain -// Passing a value of -1 is a (successful) no-op -// NOTE: DOES NOT SET VCPU's rrs[x] value!! -int set_one_rr(unsigned long rr, unsigned long val) -{ - struct vcpu *v = current; - unsigned long rreg = REGION_NUMBER(rr); - ia64_rr rrv, newrrv, memrrv; - unsigned long newrid; - - if (val == -1) return 1; - - rrv.rrval = val; - newrrv.rrval = 0; - newrid = v->arch.starting_rid + rrv.rid; - - if (newrid > v->arch.ending_rid) { - printk("can't set rr%d to %lx, starting_rid=%lx," - "ending_rid=%lx, val=%lx\n", rreg, newrid, - v->arch.starting_rid,v->arch.ending_rid,val); - return 0; - } - -#ifdef CONFIG_VTI - memrrv.rrval = rrv.rrval; - if (rreg == 7) { - newrrv.rid = newrid; - newrrv.ve = VHPT_ENABLED_REGION_7; - newrrv.ps = IA64_GRANULE_SHIFT; - ia64_new_rr7(vmMangleRID(newrrv.rrval),v->vcpu_info, - v->vcpu_info->arch.privregs); - } - else { - newrrv.rid = newrid; - // FIXME? region 6 needs to be uncached for EFI to work - if (rreg == 6) newrrv.ve = VHPT_ENABLED_REGION_7; - else newrrv.ve = VHPT_ENABLED_REGION_0_TO_6; - newrrv.ps = PAGE_SHIFT; - if (rreg == 0) v->arch.metaphysical_saved_rr0 = newrrv.rrval; - set_rr(rr,newrrv.rrval); - } -#else - memrrv.rrval = rrv.rrval; - newrrv.rid = newrid; - newrrv.ve = 1; // VHPT now enabled for region 7!! - newrrv.ps = PAGE_SHIFT; - if (rreg == 0) v->arch.metaphysical_saved_rr0 = newrrv.rrval; - if (rreg == 7) ia64_new_rr7(vmMangleRID(newrrv.rrval),v->vcpu_info, - v->vcpu_info->arch.privregs); - else set_rr(rr,newrrv.rrval); -#endif - return 1; -} - -// set rr0 to the passed rid (for metaphysical mode so don't use domain offset -int set_metaphysical_rr0(void) -{ - struct vcpu *v = current; - ia64_rr rrv; - -// rrv.ve = 1; FIXME: TURN ME BACK ON WHEN VHPT IS WORKING - set_rr(0,v->arch.metaphysical_rr0); -} - -// validates/changes region registers 0-6 in the currently executing domain -// Note that this is the one and only SP API (other than executing a privop) -// for a domain to use to change region registers -int set_all_rr( u64 rr0, u64 rr1, u64 rr2, u64 rr3, - u64 rr4, u64 rr5, u64 rr6, u64 rr7) -{ - if (!set_one_rr(0x0000000000000000L, rr0)) return 0; - if (!set_one_rr(0x2000000000000000L, rr1)) return 0; - if (!set_one_rr(0x4000000000000000L, rr2)) return 0; - if (!set_one_rr(0x6000000000000000L, rr3)) return 0; - if (!set_one_rr(0x8000000000000000L, rr4)) return 0; - if (!set_one_rr(0xa000000000000000L, rr5)) return 0; - if (!set_one_rr(0xc000000000000000L, rr6)) return 0; - if (!set_one_rr(0xe000000000000000L, rr7)) return 0; - return 1; -} - -void init_all_rr(struct vcpu *v) -{ - ia64_rr rrv; - - rrv.rrval = 0; - rrv.rrval = v->domain->arch.metaphysical_rr0; - rrv.ps = PAGE_SHIFT; - rrv.ve = 1; -if (!v->vcpu_info) { printf("Stopping in init_all_rr\n"); dummy(); } - VCPU(v,rrs[0]) = -1; - VCPU(v,rrs[1]) = rrv.rrval; - VCPU(v,rrs[2]) = rrv.rrval; - VCPU(v,rrs[3]) = rrv.rrval; - VCPU(v,rrs[4]) = rrv.rrval; - VCPU(v,rrs[5]) = rrv.rrval; - rrv.ve = 0; - VCPU(v,rrs[6]) = rrv.rrval; -// v->shared_info->arch.rrs[7] = rrv.rrval; -} - - -/* XEN/ia64 INTERNAL ROUTINES */ - -unsigned long physicalize_rid(struct vcpu *v, unsigned long rrval) -{ - ia64_rr rrv; - - rrv.rrval = rrval; - rrv.rid += v->arch.starting_rid; - return rrv.rrval; -} - -unsigned long -virtualize_rid(struct vcpu *v, unsigned long rrval) -{ - ia64_rr rrv; - - rrv.rrval = rrval; - rrv.rid -= v->arch.starting_rid; - return rrv.rrval; -} - -// loads a thread's region register (0-6) state into -// the real physical region registers. Returns the -// (possibly mangled) bits to store into rr7 -// iff it is different than what is currently in physical -// rr7 (because we have to to assembly and physical mode -// to change rr7). If no change to rr7 is required, returns 0. -// -unsigned long load_region_regs(struct vcpu *v) -{ - unsigned long rr0, rr1,rr2, rr3, rr4, rr5, rr6, rr7; - // TODO: These probably should be validated - unsigned long bad = 0; - - if (VCPU(v,metaphysical_mode)) { - ia64_rr rrv; - - rrv.rrval = 0; - rrv.rid = v->domain->arch.metaphysical_rr0; - rrv.ps = PAGE_SHIFT; - rrv.ve = 1; - rr0 = rrv.rrval; - set_rr_no_srlz(0x0000000000000000L, rr0); - ia64_srlz_d(); - } - else { - rr0 = VCPU(v,rrs[0]); - if (!set_one_rr(0x0000000000000000L, rr0)) bad |= 1; - } - rr1 = VCPU(v,rrs[1]); - rr2 = VCPU(v,rrs[2]); - rr3 = VCPU(v,rrs[3]); - rr4 = VCPU(v,rrs[4]); - rr5 = VCPU(v,rrs[5]); - rr6 = VCPU(v,rrs[6]); - rr7 = VCPU(v,rrs[7]); - if (!set_one_rr(0x2000000000000000L, rr1)) bad |= 2; - if (!set_one_rr(0x4000000000000000L, rr2)) bad |= 4; - if (!set_one_rr(0x6000000000000000L, rr3)) bad |= 8; - if (!set_one_rr(0x8000000000000000L, rr4)) bad |= 0x10; - if (!set_one_rr(0xa000000000000000L, rr5)) bad |= 0x20; - if (!set_one_rr(0xc000000000000000L, rr6)) bad |= 0x40; - if (!set_one_rr(0xe000000000000000L, rr7)) bad |= 0x80; - if (bad) { - panic_domain(0,"load_region_regs: can't set! bad=%lx\n",bad); - } - return 0; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/sn_console.c --- a/xen/arch/ia64/sn_console.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,84 +0,0 @@ -/* - * C-Brick Serial Port (and console) driver for SGI Altix machines. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include <asm/acpi.h> -#include <asm/sn/sn_sal.h> -#include <xen/serial.h> - -void sn_putc(struct serial_port *, char); - -static struct uart_driver sn_sal_console = { - .putc = sn_putc, -}; - -/** - * early_sn_setup - early setup routine for SN platforms - * - * pulled from arch/ia64/sn/kernel/setup.c - */ -static void __init early_sn_setup(void) -{ - efi_system_table_t *efi_systab; - efi_config_table_t *config_tables; - struct ia64_sal_systab *sal_systab; - struct ia64_sal_desc_entry_point *ep; - char *p; - int i, j; - - /* - * Parse enough of the SAL tables to locate the SAL entry point. Since, console - * IO on SN2 is done via SAL calls, early_printk won't work without this. - * - * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c. - * Any changes to those file may have to be made hereas well. - */ - efi_systab = (efi_system_table_t *) __va(ia64_boot_param->efi_systab); - config_tables = __va(efi_systab->tables); - for (i = 0; i < efi_systab->nr_tables; i++) { - if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == - 0) { - sal_systab = __va(config_tables[i].table); - p = (char *)(sal_systab + 1); - for (j = 0; j < sal_systab->entry_count; j++) { - if (*p == SAL_DESC_ENTRY_POINT) { - ep = (struct ia64_sal_desc_entry_point - *)p; - ia64_sal_handler_init(__va - (ep->sal_proc), - __va(ep->gp)); - return; - } - p += SAL_DESC_SIZE(*p); - } - } - } - /* Uh-oh, SAL not available?? */ - printk(KERN_ERR "failed to find SAL entry point\n"); -} - -/** - * sn_serial_console_early_setup - Sets up early console output support - * - * pulled from drivers/serial/sn_console.c - */ -int __init sn_serial_console_early_setup(void) -{ - if (strcmp("sn2",acpi_get_sysname())) - return -1; - - early_sn_setup(); /* Find SAL entry points */ - serial_register_uart(0, &sn_sal_console, NULL); - - return 0; -} - -/* - * sn_putc - Send a character to the console, polled or interrupt mode - */ -void sn_putc(struct serial_port *port, char c) -{ - return ia64_sn_console_putc(c); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vcpu.c --- a/xen/arch/ia64/vcpu.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1843 +0,0 @@ -/* - * Virtualized CPU functions - * - * Copyright (C) 2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <linux/sched.h> -#include <public/arch-ia64.h> -#include <asm/ia64_int.h> -#include <asm/vcpu.h> -#include <asm/regionreg.h> -#include <asm/tlb.h> -#include <asm/processor.h> -#include <asm/delay.h> -#include <asm/vmx_vcpu.h> - -typedef union { - struct ia64_psr ia64_psr; - unsigned long i64; -} PSR; - -//typedef struct pt_regs REGS; -//typedef struct domain VCPU; - -// this def for vcpu_regs won't work if kernel stack is present -#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs) -#define PSCB(x,y) VCPU(x,y) -#define PSCBX(x,y) x->arch.y - -#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 STATIC - -#ifdef PRIVOP_ADDR_COUNT -struct privop_addr_count privop_addr_counter[PRIVOP_COUNT_NINSTS] = { - { "=ifa", { 0 }, { 0 }, 0 }, - { "thash", { 0 }, { 0 }, 0 }, - 0 -}; -extern void privop_count_addr(unsigned long addr, int inst); -#define PRIVOP_COUNT_ADDR(regs,inst) privop_count_addr(regs->cr_iip,inst) -#else -#define PRIVOP_COUNT_ADDR(x,y) do {} while (0) -#endif - -unsigned long dtlb_translate_count = 0; -unsigned long tr_translate_count = 0; -unsigned long phys_translate_count = 0; - -unsigned long vcpu_verbose = 0; -#define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) - -extern TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa); -extern TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa); - -/************************************************************************** - VCPU general register access routines -**************************************************************************/ - -UINT64 -vcpu_get_gr(VCPU *vcpu, unsigned reg) -{ - REGS *regs = vcpu_regs(vcpu); - UINT64 val; - - if (!reg) return 0; - getreg(reg,&val,0,regs); // FIXME: handle NATs later - return 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 reg, UINT64 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 - return IA64_NO_FAULT; -} - -/************************************************************************** - VCPU privileged application register access routines -**************************************************************************/ - -IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val) -{ - 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); - else PSCB(vcpu,krs[reg]) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *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]); - return IA64_NO_FAULT; -} - -/************************************************************************** - VCPU processor status register access routines -**************************************************************************/ - -void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode) -{ - /* only do something if mode changes */ - if (!!newmode ^ !!PSCB(vcpu,metaphysical_mode)) { - if (newmode) set_metaphysical_rr0(); - else if (PSCB(vcpu,rrs[0]) != -1) - set_one_rr(0, PSCB(vcpu,rrs[0])); - PSCB(vcpu,metaphysical_mode) = newmode; - } -} - -IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu) -{ - vcpu_set_metaphysical_mode(vcpu,TRUE); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) -{ - struct ia64_psr psr, imm, *ipsr; - REGS *regs = vcpu_regs(vcpu); - - //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"); - ipsr = (struct ia64_psr *)®s->cr_ipsr; - imm = *(struct ia64_psr *)&imm24; - // interrupt flag - if (imm.i) PSCB(vcpu,interrupt_delivery_enabled) = 0; - 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 (imm.pp) { ipsr->pp = 0; psr.pp = 0; } - 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; -} - -extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu); -#define SPURIOUS_VECTOR 0xf - -IA64FAULT vcpu_set_psr_dt(VCPU *vcpu) -{ - vcpu_set_metaphysical_mode(vcpu,FALSE); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_psr_i(VCPU *vcpu) -{ - PSCB(vcpu,interrupt_delivery_enabled) = 1; - PSCB(vcpu,interrupt_collection_enabled) = 1; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) -{ - struct ia64_psr psr, imm, *ipsr; - REGS *regs = vcpu_regs(vcpu); - UINT64 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"); - 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; - if (imm.pp) { ipsr->pp = 1; psr.pp = 1; } - if (imm.sp) { ipsr->sp = 1; psr.sp = 1; } - if (imm.i) { - if (!PSCB(vcpu,interrupt_delivery_enabled)) { -//printf("vcpu_set_psr_sm: psr.ic 0->1 "); - enabling_interrupts = 1; - } - PSCB(vcpu,interrupt_delivery_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.be) { - printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n"); - 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 0 // now done with deliver_pending_interrupts - if (enabling_interrupts) { - if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) { -//printf("with interrupts pending\n"); - return IA64_EXTINT_VECTOR; - } -//else printf("but nothing pending\n"); - } -#endif - if (enabling_interrupts && - 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) -{ - struct ia64_psr psr, newpsr, *ipsr; - REGS *regs = vcpu_regs(vcpu); - UINT64 enabling_interrupts = 0; - - // TODO: All of these bits need to be virtualized - __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); - // 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.pp) { ipsr->pp = 1; psr.pp = 1; } - if (newpsr.up) { ipsr->up = 1; psr.up = 1; } - if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; } - if (newpsr.i) { - if (!PSCB(vcpu,interrupt_delivery_enabled)) - enabling_interrupts = 1; - PSCB(vcpu,interrupt_delivery_enabled) = 1; - } - 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); - } - //__asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); -#if 0 // now done with deliver_pending_interrupts - if (enabling_interrupts) { - if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - return IA64_EXTINT_VECTOR; - } -#endif - if (enabling_interrupts && - vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval) -{ - UINT64 psr; - struct ia64_psr newpsr; - - // TODO: This needs to return a "filtered" view of - // the psr, not the actual psr. Probably the psr needs - // to be a field in regs (in addition to ipsr). - __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); - newpsr = *(struct ia64_psr *)&psr; - if (newpsr.cpl == 2) newpsr.cpl = 0; - if (PSCB(vcpu,interrupt_delivery_enabled)) newpsr.i = 1; - else newpsr.i = 0; - if (PSCB(vcpu,interrupt_collection_enabled)) newpsr.ic = 1; - else newpsr.ic = 0; - *pval = *(unsigned long *)&newpsr; - return IA64_NO_FAULT; -} - -BOOLEAN vcpu_get_psr_ic(VCPU *vcpu) -{ - return !!PSCB(vcpu,interrupt_collection_enabled); -} - -BOOLEAN vcpu_get_psr_i(VCPU *vcpu) -{ - return !!PSCB(vcpu,interrupt_delivery_enabled); -} - -UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) -{ - UINT64 dcr = PSCBX(vcpu,dcr); - PSR psr = {0}; - - //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",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.i = PSCB(vcpu,interrupt_delivery_enabled); - 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...",psr.i64); - return psr.i64; -} - -/************************************************************************** - VCPU control register access routines -**************************************************************************/ - -IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval) -{ -extern unsigned long privop_trace; -//privop_trace=0; -//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); -} - -IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCBX(vcpu,iva) & ~0x7fffL; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,pta); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval) -{ - //REGS *regs = vcpu_regs(vcpu); - //*pval = regs->cr_ipsr; - *pval = PSCB(vcpu,ipsr); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,isr); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval) -{ - //REGS *regs = vcpu_regs(vcpu); - //*pval = regs->cr_iip; - *pval = PSCB(vcpu,iip); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval) -{ - UINT64 val = PSCB(vcpu,ifa); - REGS *regs = vcpu_regs(vcpu); - PRIVOP_COUNT_ADDR(regs,_GET_IFA); - *pval = val; - return (IA64_NO_FAULT); -} - -unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) -{ - ia64_rr rr; - - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.ps); -} - -unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr) -{ - ia64_rr rr; - - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.rid); -} - -unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 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); -} - - -IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval) -{ - UINT64 val = PSCB(vcpu,itir); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval) -{ - UINT64 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); -} - -IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *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); -} - -IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval) -{ - UINT64 val = PSCB(vcpu,iim); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval) -{ - //return vcpu_thash(vcpu,PSCB(vcpu,ifa),pval); - UINT64 val = PSCB(vcpu,iha); - REGS *regs = vcpu_regs(vcpu); - PRIVOP_COUNT_ADDR(regs,_THASH); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val) -{ -extern unsigned long privop_trace; -//privop_trace=1; - // 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); -} - -IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val) -{ - PSCBX(vcpu,iva) = val & ~0x7fffL; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val) -{ - if (val & IA64_PTA_LFMT) { - printf("*** No support for VHPT long format yet!!\n"); - 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; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,ipsr) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,isr) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,iip) = val; - return IA64_NO_FAULT; -} - -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); -} - -IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,ifa) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,itir) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 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; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val) -{ - //REGS *regs = vcpu_regs(vcpu); - PSCB(vcpu,ifs) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,iim) = val; - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val) -{ - PSCB(vcpu,iha) = val; - return IA64_NO_FAULT; -} - -/************************************************************************** - VCPU interrupt control register access routines -**************************************************************************/ - -void vcpu_pend_unspecified_interrupt(VCPU *vcpu) -{ - PSCB(vcpu,pending_interruption) = 1; -} - -void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) -{ - if (vector & ~0xff) { - printf("vcpu_pend_interrupt: bad vector\n"); - return; - } -#ifdef CONFIG_VTI - if ( VMX_DOMAIN(vcpu) ) { - set_bit(vector,VPD_CR(vcpu,irr)); - } else -#endif // CONFIG_VTI - { - /* if (!test_bit(vector,PSCB(vcpu,delivery_mask))) return; */ - if (test_bit(vector,PSCBX(vcpu,irr))) { -//printf("vcpu_pend_interrupt: overrun\n"); - } - set_bit(vector,PSCBX(vcpu,irr)); - PSCB(vcpu,pending_interruption) = 1; - } - -#if 0 - /* Keir: I think you should unblock when an interrupt is pending. */ - { - int running = test_bit(_VCPUF_running, &vcpu->vcpu_flags); - vcpu_unblock(vcpu); - if ( running ) - smp_send_event_check_cpu(vcpu->processor); - } -#endif -} - -void early_tick(VCPU *vcpu) -{ - UINT64 *p = &PSCBX(vcpu,irr[3]); - printf("vcpu_check_pending: about to deliver early tick\n"); - printf("&irr[0]=%p, irr[0]=0x%lx\n",p,*p); -} - -#define IA64_TPR_MMI 0x10000 -#define IA64_TPR_MIC 0x000f0 - -/* checks to see if a VCPU has any unmasked pending interrupts - * if so, returns the highest, else returns SPURIOUS_VECTOR */ -/* NOTE: Since this gets called from vcpu_get_ivr() and the - * 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) -{ - UINT64 *p, *q, *r, bits, bitnum, mask, i, vector; - - p = &PSCBX(vcpu,irr[3]); - /* q = &PSCB(vcpu,delivery_mask[3]); */ - r = &PSCBX(vcpu,insvc[3]); - for (i = 3; ; p--, q--, r--, i--) { - bits = *p /* & *q */; - 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 - 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...",bitnum); - vector = bitnum+(i*64); - mask = 1L << bitnum; -//printf("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...",vector); - if (*r >= mask) { - // masked by equal inservice -//printf("but masked by equal inservice\n"); - return SPURIOUS_VECTOR; - } - 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) { - //tpr.mic masks class -//printf("but masked by tpr.mic\n"); - return SPURIOUS_VECTOR; - } - -//printf("returned to caller\n"); -#if 0 -if (vector == (PSCB(vcpu,itv) & 0xff)) { - UINT64 now = ia64_get_itc(); - UINT64 itm = PSCBX(vcpu,domain_itm); - if (now < itm) early_tick(vcpu); - -} -#endif - return vector; -} - -UINT64 vcpu_deliverable_interrupts(VCPU *vcpu) -{ - return (vcpu_get_psr_i(vcpu) && - vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR); -} - -UINT64 vcpu_deliverable_timer(VCPU *vcpu) -{ - return (vcpu_get_psr_i(vcpu) && - vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu,itv)); -} - -IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval) -{ -extern unsigned long privop_trace; -//privop_trace=1; - //TODO: Implement this - printf("vcpu_get_lid: WARNING: Getting cr.lid always returns zero\n"); - //*pval = 0; - *pval = ia64_getreg(_IA64_REG_CR_LID); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) -{ - int i; - UINT64 vector, mask; - -#define HEARTBEAT_FREQ 16 // period in seconds -#ifdef HEARTBEAT_FREQ -#define N_DOMS 16 // period in seconds - static long count[N_DOMS] = { 0 }; - static long nonclockcount[N_DOMS] = { 0 }; - REGS *regs = vcpu_regs(vcpu); - unsigned domid = vcpu->domain->domain_id; -#endif -#ifdef IRQ_DEBUG - static char firstivr = 1; - static char firsttime[256]; - if (firstivr) { - int i; - 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; - *pval = vector; - return IA64_NO_FAULT; - } -#ifdef HEARTBEAT_FREQ - if (domid >= N_DOMS) domid = N_DOMS-1; - 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(); - } - } - 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=%d,itc=%lx\n", - vector,ia64_get_itc()); - firsttime[vector]=0; - } -#endif - i = vector >> 6; - mask = 1L << (vector & 0x3f); -//printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector); - PSCBX(vcpu,insvc[i]) |= mask; - PSCBX(vcpu,irr[i]) &= ~mask; - //PSCB(vcpu,pending_interruption)--; - *pval = vector; - // if delivering a timer interrupt, remember domain_itm - if (vector == (PSCB(vcpu,itv) & 0xff)) { - PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm); - } - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,tpr); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval) -{ - *pval = 0L; // reads of eoi always return 0 - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval) -{ -#ifndef IRR_USE_FIXED - printk("vcpu_get_irr: called, not implemented yet\n"); - return IA64_ILLOP_FAULT; -#else - *pval = vcpu->irr[0]; - return (IA64_NO_FAULT); -#endif -} - -IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval) -{ -#ifndef IRR_USE_FIXED - printk("vcpu_get_irr: called, not implemented yet\n"); - return IA64_ILLOP_FAULT; -#else - *pval = vcpu->irr[1]; - return (IA64_NO_FAULT); -#endif -} - -IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval) -{ -#ifndef IRR_USE_FIXED - printk("vcpu_get_irr: called, not implemented yet\n"); - return IA64_ILLOP_FAULT; -#else - *pval = vcpu->irr[2]; - return (IA64_NO_FAULT); -#endif -} - -IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval) -{ -#ifndef IRR_USE_FIXED - printk("vcpu_get_irr: called, not implemented yet\n"); - return IA64_ILLOP_FAULT; -#else - *pval = vcpu->irr[3]; - return (IA64_NO_FAULT); -#endif -} - -IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,itv); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,pmv); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval) -{ - *pval = PSCB(vcpu,cmcv); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *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); -} - -IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *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); -} - -IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val) -{ - printf("vcpu_set_lid: Setting cr.lid is unsupported\n"); - return (IA64_ILLOP_FAULT); -} - -IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val) -{ - if (val & 0xff00) return IA64_RSVDREG_FAULT; - PSCB(vcpu,tpr) = val; - if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val) -{ - UINT64 *p, bits, vec, bitnum; - int i; - - 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.\r\n"); - return; - } - bitnum = ia64_fls(bits); - vec = bitnum + (i*64); - /* clear the correct bit */ - bits &= ~(1L << bitnum); - *p = bits; - /* clearing an eoi bit may unmask another pending interrupt... */ - if (PSCB(vcpu,interrupt_delivery_enabled)) { // but only if enabled... - // worry about this later... Linux only calls eoi - // with interrupts disabled - printf("Trying to EOI interrupt with interrupts enabled\r\n"); - } - if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; -//printf("YYYYY vcpu_set_eoi: Successful\n"); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val) -{ - if (!(val & (1L << 16))) { - printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); - return (IA64_ILLOP_FAULT); - } - // no place to save this state but nothing to do anyway - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val) -{ - if (!(val & (1L << 16))) { - printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); - return (IA64_ILLOP_FAULT); - } - // no place to save this state but nothing to do anyway - return (IA64_NO_FAULT); -} - -// parameter is a time interval specified in cycles -void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles) -{ - PSCBX(vcpu,xen_timer_interval) = cycles; - vcpu_set_next_timer(vcpu); - printf("vcpu_enable_timer(%d): interval set to %d cycles\n", - PSCBX(vcpu,xen_timer_interval)); - __set_bit(PSCB(vcpu,itv), PSCB(vcpu,delivery_mask)); -} - -IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val) -{ -extern unsigned long privop_trace; -//privop_trace=1; - if (val & 0xef00) return (IA64_ILLOP_FAULT); - PSCB(vcpu,itv) = val; - if (val & 0x10000) { -printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCBX(vcpu,domain_itm)); - PSCBX(vcpu,domain_itm) = 0; - } - else vcpu_enable_timer(vcpu,1000000L); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val) -{ - 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) -{ - 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) -{ - if (index > 7) return 0; - return PSCB(vcpu,tmp[index]); -} - -void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val) -{ - if (index <= 7) PSCB(vcpu,tmp[index]) = val; -} - -/************************************************************************** -Interval timer routines -**************************************************************************/ - -BOOLEAN vcpu_timer_disabled(VCPU *vcpu) -{ - UINT64 itv = PSCB(vcpu,itv); - return(!itv || !!(itv & 0x10000)); -} - -BOOLEAN vcpu_timer_inservice(VCPU *vcpu) -{ - UINT64 itv = PSCB(vcpu,itv); - return (test_bit(itv, PSCBX(vcpu,insvc))); -} - -BOOLEAN vcpu_timer_expired(VCPU *vcpu) -{ - 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; - return TRUE; -} - -void vcpu_safe_set_itm(unsigned long val) -{ - unsigned long epsilon = 100; - UINT64 now = ia64_get_itc(); - - local_irq_disable(); - 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; - val = now + epsilon; - epsilon <<= 1; - } - local_irq_enable(); -} - -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(); - //UINT64 interval = PSCBX(vcpu,xen_timer_interval); - - /* gloss over the wraparound problem for now... we know it exists - * but it doesn't matter right now */ - -#if 0 - /* ensure at least next SP tick is in the future */ - if (!interval) PSCBX(vcpu,xen_itm) = now + -#if 0 - (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE : - DEFAULT_CLOCK_RATE); -#else - 3000000; -//printf("vcpu_set_next_timer: HACK!\n"); -#endif -#if 0 - if (PSCBX(vcpu,xen_itm) < now) - while (PSCBX(vcpu,xen_itm) < now + (interval>>1)) - PSCBX(vcpu,xen_itm) += interval; -#endif -#endif - - if (is_idle_task(vcpu->domain)) { - printf("****** vcpu_set_next_timer called during idle!!\n"); - } - //s = PSCBX(vcpu,xen_itm); - if (d && (d > now) && (d < s)) { - vcpu_safe_set_itm(d); - //using_domain_as_itm++; - } - else { - vcpu_safe_set_itm(s); - //using_xen_as_itm++; - } -} - -IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 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; - vcpu_set_next_timer(vcpu); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) -{ - - UINT64 oldnow = ia64_get_itc(); - UINT64 olditm = PSCBX(vcpu,domain_itm); - unsigned long d = olditm - oldnow; - unsigned long x = local_cpu_data->itm_next - oldnow; - - UINT64 newnow = val, min_delta; - -#define DISALLOW_SETTING_ITC_FOR_NOW -#ifdef DISALLOW_SETTING_ITC_FOR_NOW -printf("vcpu_set_itc: Setting ar.itc is currently disabled\n"); -#else - local_irq_disable(); - if (olditm) { -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); - 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 { - vcpu_safe_set_itm(x); - //using_xen_as_itm++; - } - local_irq_enable(); -#endif - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval) -{ - //FIXME: Implement this - printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n"); - return (IA64_NO_FAULT); - //return (IA64_ILLOP_FAULT); -} - -IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval) -{ - //TODO: Implement this - printf("vcpu_get_itc: Getting ar.itc is unsupported\n"); - return (IA64_ILLOP_FAULT); -} - -void vcpu_pend_timer(VCPU *vcpu) -{ - UINT64 itv = PSCB(vcpu,itv) & 0xff; - - if (vcpu_timer_disabled(vcpu)) return; - //if (vcpu_timer_inservice(vcpu)) return; - if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) { - // already delivered an interrupt for this so - // don't deliver another - return; - } -#if 0 - // attempt to flag "timer tick before its due" source - { - UINT64 itm = PSCBX(vcpu,domain_itm); - UINT64 now = ia64_get_itc(); - if (now < itm) printf("******* vcpu_pend_timer: pending before due!\n"); - } -#endif - vcpu_pend_interrupt(vcpu, itv); -} - -// returns true if ready to deliver a timer interrupt too early -UINT64 vcpu_timer_pending_early(VCPU *vcpu) -{ - UINT64 now = ia64_get_itc(); - UINT64 itm = PSCBX(vcpu,domain_itm); - - if (vcpu_timer_disabled(vcpu)) return 0; - if (!itm) return 0; - return (vcpu_deliverable_timer(vcpu) && (now < itm)); -} - -//FIXME: This is a hack because everything dies if a timer tick is lost -void vcpu_poke_timer(VCPU *vcpu) -{ - UINT64 itv = PSCB(vcpu,itv) & 0xff; - UINT64 now = ia64_get_itc(); - UINT64 itm = PSCBX(vcpu,domain_itm); - UINT64 irr; - - if (vcpu_timer_disabled(vcpu)) return; - if (!itm) return; - if (itv != 0xefL) { - printf("vcpu_poke_timer: unimplemented itv=%lx!\n",itv); - while(1); - } - // using 0xef instead of itv so can get real irr - if (now > itm && !test_bit(0xefL, PSCBX(vcpu,insvc))) { - if (!test_bit(0xefL,PSCBX(vcpu,irr))) { - irr = ia64_getreg(_IA64_REG_CR_IRR3); - if (irr & (1L<<(0xef-0xc0))) return; -if (now-itm>0x800000) -printf("*** poking timer: now=%lx,vitm=%lx,xitm=%lx,itm=%lx\n",now,itm,local_cpu_data->itm_next,ia64_get_itm()); - vcpu_pend_timer(vcpu); - } - } -} - - -/************************************************************************** -Privileged operation emulation routines -**************************************************************************/ - -IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa) -{ - PSCB(vcpu,tmp[0]) = ifa; // save ifa in vcpu structure, then specify IA64_FORCED_IFA - return (vcpu_get_rr_ve(vcpu,ifa) ? IA64_DATA_TLB_VECTOR : IA64_ALT_DATA_TLB_VECTOR) | IA64_FORCED_IFA; -} - - -IA64FAULT vcpu_rfi(VCPU *vcpu) -{ - // TODO: Only allowed for current vcpu - PSR psr; - UINT64 int_enable, regspsr = 0; - UINT64 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; - if (psr.ia64_psr.i) PSCB(vcpu,interrupt_delivery_enabled) = 1; - 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; - 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); - } - 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; - // 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 { - regs->cr_ipsr = psr.i64; - regs->cr_iip = PSCB(vcpu,iip); - } - PSCB(vcpu,interrupt_collection_enabled) = 1; - vcpu_bsw1(vcpu); - PSCB(vcpu,interrupt_delivery_enabled) = int_enable; - return (IA64_NO_FAULT); -} - -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; - } - 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 = RR_TO_PS(get_rr(vadr)); - 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; - -#if 0 - if (VHPT_addr1 == 0xe000000000000000L) { - printf("vcpu_thash: thash unsupported with rr7 @%lx\n", - PSCB(vcpu,iip)); - return (IA64_ILLOP_FAULT); - } -#endif -//verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr); - *pval = VHPT_addr; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr) -{ - printf("vcpu_ttag: ttag instruction unsupported\n"); - return (IA64_ILLOP_FAULT); -} - -#define itir_ps(itir) ((itir >> 2) & 0x3f) -#define itir_mask(itir) (~((1UL << itir_ps(itir)) - 1)) - -unsigned long vhpt_translate_count = 0; - -IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir) -{ - unsigned long pta, pta_mask, iha, pte, ps; - TR_ENTRY *trp; - ia64_rr rr; - - if (!(address >> 61)) { - if (!PSCB(vcpu,metaphysical_mode)) { - REGS *regs = vcpu_regs(vcpu); - 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 %p, viip=%p, vipsr=%p, iip=%p, ipsr=%p continuing\n", address, viip, vipsr, iip, ipsr); - } - - *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX; - *itir = PAGE_SHIFT << 2; - phys_translate_count++; - return IA64_NO_FAULT; - } - - /* check translation registers */ - if ((trp = match_tr(vcpu,address))) { - tr_translate_count++; - *pteval = trp->page_flags; - *itir = trp->itir; - return IA64_NO_FAULT; - } - - /* check 1-entry TLB */ - if ((trp = match_dtlb(vcpu,address))) { - dtlb_translate_count++; - *pteval = trp->page_flags; - *itir = trp->itir; - return IA64_NO_FAULT; - } - - /* check guest VHPT */ - pta = PSCB(vcpu,pta); - rr.rrval = PSCB(vcpu,rrs)[address>>61]; - if (rr.ve && (pta & IA64_PTA_VE)) - { - if (pta & IA64_PTA_VF) - { - /* long format VHPT - not implemented */ - return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); - } - else - { - /* short format VHPT */ - - /* avoid recursively walking VHPT */ - pta_mask = (itir_mask(pta) << 3) >> 3; - if (((address ^ pta) & pta_mask) == 0) - return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); - - vcpu_thash(vcpu, address, &iha); - if (__copy_from_user(&pte, (void *)iha, sizeof(pte)) != 0) - return IA64_VHPT_TRANS_VECTOR; - - /* - * 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 & _PAGE_P) - { - *pteval = pte; - *itir = vcpu_get_itir_on_fault(vcpu,address); - vhpt_translate_count++; - return IA64_NO_FAULT; - } - return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); - } - } - return (is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR); -} - -IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) -{ - UINT64 pteval, itir, mask; - IA64FAULT fault; - - fault = vcpu_translate(vcpu, vadr, 1, &pteval, &itir); - if (fault == IA64_NO_FAULT) - { - mask = itir_mask(itir); - *padr = (pteval & _PAGE_PPN_MASK & mask) | (vadr & ~mask); - return (IA64_NO_FAULT); - } - else - { - PSCB(vcpu,tmp[0]) = vadr; // save ifa in vcpu structure, then specify IA64_FORCED_IFA - return (fault | IA64_FORCED_IFA); - } -} - -IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) -{ - printf("vcpu_tak: tak instruction unsupported\n"); - return (IA64_ILLOP_FAULT); - // HACK ALERT: tak does a thash for now - //return vcpu_thash(vcpu,vadr,key); -} - -/************************************************************************** - VCPU debug breakpoint register access routines -**************************************************************************/ - -IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 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); -} - -IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 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); -} - -IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - // TODO: unimplemented DBRs return a reserved register fault - UINT64 val = ia64_get_dbr(reg); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - // TODO: unimplemented IBRs return a reserved register fault - UINT64 val = ia64_get_ibr(reg); - *pval = val; - return (IA64_NO_FAULT); -} - -/************************************************************************** - VCPU performance monitor register access routines -**************************************************************************/ - -IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 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); -} - -IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 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); -} - -IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - // NOTE: Reads from unimplemented PMC registers return zero - UINT64 val = (UINT64)ia64_get_pmc(reg); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - // NOTE: Reads from unimplemented PMD registers return zero - UINT64 val = (UINT64)ia64_get_pmd(reg); - *pval = val; - return (IA64_NO_FAULT); -} - -/************************************************************************** - VCPU banked general register access routines -**************************************************************************/ - -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]); - int i; - - if (PSCB(vcpu,banknum)) { - for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; } - PSCB(vcpu,banknum) = 0; - } - return (IA64_NO_FAULT); -} - -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]); - int i; - - if (!PSCB(vcpu,banknum)) { - for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; } - PSCB(vcpu,banknum) = 1; - } - return (IA64_NO_FAULT); -} - -/************************************************************************** - VCPU cpuid access routines -**************************************************************************/ - - -IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *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); - break; - case 1: - *pval = 0; - break; - case 2: - *pval = 0; - break; - case 3: - *pval = ia64_get_cpuid(3); - break; - case 4: - *pval = ia64_get_cpuid(4); - break; - default: - if (reg > (ia64_get_cpuid(3) & 0xff)) - return IA64_RSVDREG_FAULT; - *pval = ia64_get_cpuid(reg); - break; - } - return (IA64_NO_FAULT); -} - -/************************************************************************** - VCPU region register access routines -**************************************************************************/ - -unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) -{ - ia64_rr rr; - - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.ve); -} - -IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) -{ - PSCB(vcpu,rrs)[reg>>61] = val; - // warning: set_one_rr() does it "live" - set_one_rr(reg,val); - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - UINT val = PSCB(vcpu,rrs)[reg>>61]; - *pval = val; - return (IA64_NO_FAULT); -} - -/************************************************************************** - VCPU protection key register access routines -**************************************************************************/ - -IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *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); - *pval = val; - return (IA64_NO_FAULT); -#endif -} - -IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 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); - vcpu->pkrs[reg] = val; - ia64_set_pkr(reg,val); - return (IA64_NO_FAULT); -#endif -} - -/************************************************************************** - VCPU translation register access routines -**************************************************************************/ - -static void vcpu_purge_tr_entry(TR_ENTRY *trp) -{ - trp->p = 0; -} - -static void vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa) -{ - UINT64 ps; - - trp->itir = itir; - trp->rid = virtualize_rid(current, get_rr(ifa) & RR_RID_MASK); - trp->p = 1; - ps = trp->ps; - trp->page_flags = pte; - if (trp->pl < 2) trp->pl = 2; - trp->vadr = ifa & ~0xfff; - if (ps > 12) { // "ignore" relevant low-order bits - trp->ppn &= ~((1UL<<(ps-12))-1); - trp->vadr &= ~((1UL<<ps)-1); - } -} - -TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count) -{ - unsigned long rid = (get_rr(ifa) & RR_RID_MASK); - int i; - - for (i = 0; i < count; i++, trp++) { - if (!trp->p) continue; - if (physicalize_rid(vcpu,trp->rid) != rid) continue; - if (ifa < trp->vadr) continue; - if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; - //if (trp->key && !match_pkr(vcpu,trp->key)) continue; - return trp; - } - return 0; -} - -TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa) -{ - TR_ENTRY *trp; - - trp = vcpu_match_tr_entry(vcpu,vcpu->arch.dtrs,ifa,NDTRS); - if (trp) return trp; - trp = vcpu_match_tr_entry(vcpu,vcpu->arch.itrs,ifa,NITRS); - if (trp) return trp; - return 0; -} - -IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) -{ - TR_ENTRY *trp; - - if (slot >= NDTRS) return IA64_RSVDREG_FAULT; - trp = &PSCBX(vcpu,dtrs[slot]); -//printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa); - vcpu_set_tr_entry(trp,pte,itir,ifa); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) -{ - TR_ENTRY *trp; - - if (slot >= NITRS) return IA64_RSVDREG_FAULT; - trp = &PSCBX(vcpu,itrs[slot]); -//printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa); - vcpu_set_tr_entry(trp,pte,itir,ifa); - return IA64_NO_FAULT; -} - -/************************************************************************** - VCPU translation cache access routines -**************************************************************************/ - -void foobar(void) { /*vcpu_verbose = 1;*/ } - -extern struct domain *dom0; - -void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 mp_pte, UINT64 logps) -{ - unsigned long psr; - unsigned long ps = (vcpu->domain==dom0) ? logps : PAGE_SHIFT; - - // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK! - // FIXME, must be inlined or potential for nested fault here! - if ((vcpu->domain==dom0) && (logps < PAGE_SHIFT)) { - printf("vcpu_itc_no_srlz: domain0 use of smaller page size!\n"); - //FIXME: kill domain here - while(1); - } - psr = ia64_clear_ic(); - 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)) { - // 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); - } - // 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); -#endif - if (IorD & 0x4) return; // don't place in 1-entry TLB - if (IorD & 0x1) { - vcpu_set_tr_entry(&PSCBX(vcpu,itlb),pte,ps<<2,vaddr); - PSCBX(vcpu,itlb_pte) = mp_pte; - } - if (IorD & 0x2) { - vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),pte,ps<<2,vaddr); - PSCBX(vcpu,dtlb_pte) = mp_pte; - } -} - -// NOTE: returns a physical pte, NOT a "metaphysical" pte, so do not check -// the physical address contained for correctness -TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa) -{ - TR_ENTRY *trp; - - if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) - return (&vcpu->arch.dtlb); - return 0UL; -} - -IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) -{ - unsigned long pteval, logps = (itir >> 2) & 0x3f; - unsigned long translate_domain_pte(UINT64,UINT64,UINT64); - - if (logps < PAGE_SHIFT) { - printf("vcpu_itc_d: domain trying to use smaller page size!\n"); - //FIXME: kill domain here - while(1); - } - //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize - pteval = translate_domain_pte(pte,ifa,itir); - if (!pteval) return IA64_ILLOP_FAULT; - vcpu_itc_no_srlz(vcpu,2,ifa,pteval,pte,logps); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) -{ - unsigned long pteval, logps = (itir >> 2) & 0x3f; - unsigned long translate_domain_pte(UINT64,UINT64,UINT64); - - // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK! - if (logps < PAGE_SHIFT) { - printf("vcpu_itc_i: domain trying to use smaller page size!\n"); - //FIXME: kill domain here - while(1); - } - //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize - pteval = translate_domain_pte(pte,ifa,itir); - // FIXME: what to do if bad physical address? (machine check?) - if (!pteval) return IA64_ILLOP_FAULT; - vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,pte,logps); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 addr_range) -{ - printk("vcpu_ptc_l: called, not implemented yet\n"); - return IA64_ILLOP_FAULT; -} - -// At privlvl=0, fc performs no access rights or protection key checks, while -// at privlvl!=0, fc performs access rights checks as if it were a 1-byte -// read but no protection key check. Thus in order to avoid an unexpected -// 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) -{ - // TODO: Only allowed for current vcpu - UINT64 mpaddr, paddr; - IA64FAULT fault; - unsigned long translate_domain_mpaddr(unsigned long); - IA64FAULT vcpu_tpa(VCPU *, UINT64, UINT64 *); - - fault = vcpu_tpa(vcpu, vadr, &mpaddr); - if (fault == IA64_NO_FAULT) { - paddr = translate_domain_mpaddr(mpaddr); - ia64_fc(__va(paddr)); - } - return fault; -} - -int ptce_count = 0; -IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) -{ - // Note that this only needs to be called once, i.e. the - // architected loop to purge the entire TLB, should use - // base = stride1 = stride2 = 0, count0 = count 1 = 1 - -#ifdef VHPT_GLOBAL - vhpt_flush(); // FIXME: This is overdoing it -#endif - local_flush_tlb_all(); - // just invalidate the "whole" tlb - vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 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) -{ - extern ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits); - // 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); -#ifdef VHPT_GLOBAL - vhpt_flush_address(vadr,addr_range); -#endif - ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT); - vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); - return IA64_NO_FAULT; -} - -IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) -{ - printf("vcpu_ptr_d: Purging TLB is unsupported\n"); - return (IA64_ILLOP_FAULT); -} - -IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) -{ - printf("vcpu_ptr_i: Purging TLB is unsupported\n"); - return (IA64_ILLOP_FAULT); -} - -void vcpu_set_regs(VCPU *vcpu, REGS *regs) -{ - vcpu->arch.regs = regs; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vhpt.c --- a/xen/arch/ia64/vhpt.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,151 +0,0 @@ -/* - * Initialize VHPT support. - * - * Copyright (C) 2004 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/pgalloc.h> -#include <asm/page.h> -#include <asm/dma.h> -#include <asm/vhpt.h> - -unsigned long vhpt_paddr, vhpt_pend, vhpt_pte; - -void vhpt_flush(void) -{ - struct vhpt_lf_entry *v = (void *)VHPT_ADDR; - int i, cnt = 0; -#if 0 -static int firsttime = 2; - -if (firsttime) firsttime--; -else { -printf("vhpt_flush: *********************************************\n"); -printf("vhpt_flush: *********************************************\n"); -printf("vhpt_flush: *********************************************\n"); -printf("vhpt_flush: flushing vhpt (seems to crash at rid wrap?)...\n"); -printf("vhpt_flush: *********************************************\n"); -printf("vhpt_flush: *********************************************\n"); -printf("vhpt_flush: *********************************************\n"); -} -#endif - for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) { - v->itir = 0; - v->CChain = 0; - v->page_flags = 0; - v->ti_tag = INVALID_TI_TAG; - } - // initialize cache too??? -} - -#ifdef VHPT_GLOBAL -void vhpt_flush_address(unsigned long vadr, unsigned long addr_range) -{ - unsigned long ps; - struct vhpt_lf_entry *vlfe; - - if ((vadr >> 61) == 7) { - // no vhpt for region 7 yet, see vcpu_itc_no_srlz - printf("vhpt_flush_address: region 7, spinning...\n"); - while(1); - } -#if 0 - // this only seems to occur at shutdown, but it does occur - if ((!addr_range) || addr_range & (addr_range - 1)) { - printf("vhpt_flush_address: weird range, spinning...\n"); - while(1); - } -//printf("************** vhpt_flush_address(%p,%p)\n",vadr,addr_range); -#endif - while ((long)addr_range > 0) { - vlfe = (struct vhpt_lf_entry *)ia64_thash(vadr); - // FIXME: for now, just blow it away even if it belongs to - // another domain. Later, use ttag to check for match -//if (!(vlfe->ti_tag & INVALID_TI_TAG)) { -//printf("vhpt_flush_address: blowing away valid tag for vadr=%p\n",vadr); -//} - vlfe->ti_tag |= INVALID_TI_TAG; - addr_range -= PAGE_SIZE; - vadr += PAGE_SIZE; - } -} -#endif - -void vhpt_map(void) -{ - unsigned long psr; - - psr = ia64_clear_ic(); - ia64_itr(0x2, IA64_TR_VHPT, VHPT_ADDR, vhpt_pte, VHPT_SIZE_LOG2); - ia64_set_psr(psr); - ia64_srlz_i(); -} - -void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long logps) -{ - unsigned long mask = (1L << logps) - 1; - extern long running_on_sim; - int i; - - if (logps-PAGE_SHIFT > 10 && !running_on_sim) { - // if this happens, we may want to revisit this algorithm - printf("vhpt_multiple_insert:logps-PAGE_SHIFT>10,spinning..\n"); - while(1); - } - if (logps-PAGE_SHIFT > 2) { - // FIXME: Should add counter here to see how often this - // happens (e.g. for 16MB pages!) and determine if it - // is a performance problem. On a quick look, it takes - // about 39000 instrs for a 16MB page and it seems to occur - // only a few times/second, so OK for now. - // An alternate solution would be to just insert the one - // 16KB in the vhpt (but with the full mapping)? - //printf("vhpt_multiple_insert: logps-PAGE_SHIFT==%d," - //"va=%p, pa=%p, pa-masked=%p\n", - //logps-PAGE_SHIFT,vaddr,pte&_PFN_MASK, - //(pte&_PFN_MASK)&~mask); - } - vaddr &= ~mask; - pte = ((pte & _PFN_MASK) & ~mask) | (pte & ~_PFN_MASK); - for (i = 1L << (logps-PAGE_SHIFT); i > 0; i--) { - vhpt_insert(vaddr,pte,logps<<2); - vaddr += PAGE_SIZE; - } -} - -void vhpt_init(void) -{ - unsigned long vhpt_total_size, vhpt_alignment, vhpt_imva; -#if !VHPT_ENABLED - return; -#endif - // allocate a huge chunk of physical memory.... how??? - vhpt_total_size = 1 << VHPT_SIZE_LOG2; // 4MB, 16MB, 64MB, or 256MB - vhpt_alignment = 1 << VHPT_SIZE_LOG2; // 4MB, 16MB, 64MB, or 256MB - printf("vhpt_init: vhpt size=%p, align=%p\n",vhpt_total_size,vhpt_alignment); - /* This allocation only holds true if vhpt table is unique for - * all domains. Or else later new vhpt table should be allocated - * from domain heap when each domain is created. Assume xen buddy - * allocator can provide natural aligned page by order? - */ - vhpt_imva = alloc_xenheap_pages(VHPT_SIZE_LOG2 - PAGE_SHIFT); - if (!vhpt_imva) { - printf("vhpt_init: can't allocate VHPT!\n"); - while(1); - } - vhpt_paddr = __pa(vhpt_imva); - vhpt_pend = vhpt_paddr + vhpt_total_size - 1; - printf("vhpt_init: vhpt paddr=%p, end=%p\n",vhpt_paddr,vhpt_pend); - vhpt_pte = pte_val(pfn_pte(vhpt_paddr >> PAGE_SHIFT, PAGE_KERNEL)); - vhpt_map(); - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); - vhpt_flush(); -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vlsapic.c --- a/xen/arch/ia64/vlsapic.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,620 +0,0 @@ - -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vlsapic.c: virtual lsapic model including ITC timer. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - */ - -#include <linux/sched.h> -#include <public/arch-ia64.h> -#include <asm/ia64_int.h> -#include <asm/vcpu.h> -#include <asm/regionreg.h> -#include <asm/tlb.h> -#include <asm/processor.h> -#include <asm/delay.h> -#include <asm/vmx_vcpu.h> -#include <asm/vmx_vcpu.h> -#include <asm/regs.h> -#include <asm/gcc_intrin.h> -#include <asm/vmx_mm_def.h> -#include <asm/vmx.h> -#include <asm/hw_irq.h> -#include <asm/vmx_pal_vsa.h> -#include <asm/kregs.h> - -#define SHARED_VLAPIC_INF -#ifdef V_IOSAPIC_READY -static inline vl_apic_info* get_psapic(VCPU *vcpu) -{ - shared_iopage_t *sp = get_sp(vcpu->domain); - return &(sp->vcpu_iodata[vcpu->vcpu_id].apic_intr); -} -#endif -//u64 fire_itc; -//u64 fire_itc2; -//u64 fire_itm; -//u64 fire_itm2; -/* - * Update the checked last_itc. - */ -static void update_last_itc(vtime_t *vtm, uint64_t cur_itc) -{ - vtm->last_itc = cur_itc; -} - -/* - * ITC value saw in guest (host+offset+drift). - */ -static uint64_t now_itc(vtime_t *vtm) -{ - uint64_t guest_itc=vtm->vtm_offset+ia64_get_itc(); - - if ( vtm->vtm_local_drift ) { -// guest_itc -= vtm->vtm_local_drift; - } - if ( (long)(guest_itc - vtm->last_itc) > 0 ) { - return guest_itc; - - } - else { - /* guest ITC backwarded due after LP switch */ - return vtm->last_itc; - } -} - -/* - * Interval time components reset. - */ -static void vtm_reset(VCPU *vcpu) -{ - uint64_t cur_itc; - vtime_t *vtm; - - vtm=&(vcpu->arch.arch_vmx.vtm); - vtm->vtm_offset = 0; - vtm->vtm_local_drift = 0; - VPD_CR(vcpu, itm) = 0; - VPD_CR(vcpu, itv) = 0x10000; - cur_itc = ia64_get_itc(); - vtm->last_itc = vtm->vtm_offset + cur_itc; -} - -/* callback function when vtm_timer expires */ -static void vtm_timer_fn(void *data) -{ - vtime_t *vtm; - VCPU *vcpu = data; - u64 cur_itc,vitm; - - UINT64 vec; - - vec = VPD_CR(vcpu, itv) & 0xff; - vmx_vcpu_pend_interrupt(vcpu, vec); - - vtm=&(vcpu->arch.arch_vmx.vtm); - cur_itc = now_itc(vtm); - vitm =VPD_CR(vcpu, itm); - //fire_itc2 = cur_itc; - //fire_itm2 = vitm; - update_last_itc(vtm,cur_itc); // pseudo read to update vITC -} - -void vtm_init(VCPU *vcpu) -{ - vtime_t *vtm; - uint64_t itc_freq; - - vtm=&(vcpu->arch.arch_vmx.vtm); - - itc_freq = local_cpu_data->itc_freq; - vtm->cfg_max_jump=itc_freq*MAX_JUMP_STEP/1000; - vtm->cfg_min_grun=itc_freq*MIN_GUEST_RUNNING_TIME/1000; - init_ac_timer(&vtm->vtm_timer, vtm_timer_fn, vcpu, 0); - vtm_reset(vcpu); -} - -/* - * Action when guest read ITC. - */ -uint64_t vtm_get_itc(VCPU *vcpu) -{ - uint64_t guest_itc, spsr; - vtime_t *vtm; - - vtm=&(vcpu->arch.arch_vmx.vtm); - // FIXME: should use local_irq_disable & local_irq_enable ?? - local_irq_save(spsr); - guest_itc = now_itc(vtm); -// update_last_itc(vtm, guest_itc); - - local_irq_restore(spsr); - return guest_itc; -} - -void vtm_set_itc(VCPU *vcpu, uint64_t new_itc) -{ - uint64_t spsr; - vtime_t *vtm; - - vtm=&(vcpu->arch.arch_vmx.vtm); - local_irq_save(spsr); - vtm->vtm_offset = new_itc - ia64_get_itc(); - vtm->last_itc = new_itc; - vtm_interruption_update(vcpu, vtm); - local_irq_restore(spsr); -} - -void vtm_set_itv(VCPU *vcpu) -{ - uint64_t spsr,itv; - vtime_t *vtm; - - vtm=&(vcpu->arch.arch_vmx.vtm); - local_irq_save(spsr); - itv = VPD_CR(vcpu, itv); - if ( ITV_IRQ_MASK(itv) ) - rem_ac_timer(&vtm->vtm_timer); - vtm_interruption_update(vcpu, vtm); - local_irq_restore(spsr); -} - - -/* - * Update interrupt or hook the vtm ac_timer for fire - * At this point vtm_timer should be removed if itv is masked. - */ -/* Interrupt must be disabled at this point */ - -extern u64 tick_to_ns(u64 tick); -#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ -void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm) -{ - uint64_t cur_itc,vitm,vitv; - uint64_t expires; - long diff_now, diff_last; - uint64_t spsr; - - vitv = VPD_CR(vcpu, itv); - if ( ITV_IRQ_MASK(vitv) ) { - return; - } - - vitm =VPD_CR(vcpu, itm); - local_irq_save(spsr); - cur_itc =now_itc(vtm); - diff_last = vtm->last_itc - vitm; - diff_now = cur_itc - vitm; - update_last_itc (vtm,cur_itc); - - if ( diff_last >= 0 ) { - // interrupt already fired. - rem_ac_timer(&vtm->vtm_timer); - } - else if ( diff_now >= 0 ) { - // ITV is fired. - vmx_vcpu_pend_interrupt(vcpu, vitv&0xff); - } - /* Both last_itc & cur_itc < itm, wait for fire condition */ - else { - expires = NOW() + tick_to_ns(0-diff_now) + TIMER_SLOP; - set_ac_timer(&vtm->vtm_timer, expires); - } - local_irq_restore(spsr); -} - -/* - * Action for vtm when the domain is scheduled out. - * Remove the ac_timer for vtm. - */ -void vtm_domain_out(VCPU *vcpu) -{ - if(!is_idle_task(vcpu->domain)) - rem_ac_timer(&vcpu->arch.arch_vmx.vtm.vtm_timer); -} - -/* - * Action for vtm when the domain is scheduled in. - * Fire vtm IRQ or add the ac_timer for vtm. - */ -void vtm_domain_in(VCPU *vcpu) -{ - vtime_t *vtm; - - if(!is_idle_task(vcpu->domain)) { - vtm=&(vcpu->arch.arch_vmx.vtm); - vtm_interruption_update(vcpu, vtm); - } -} - -/* - * Next for vLSapic - */ - -#define NMI_VECTOR 2 -#define ExtINT_VECTOR 0 -#define NULL_VECTOR -1 -#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.arch_vmx.in_service[i]) -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 / 16; - } - - VMX_VPD(vcpu,vhpi) = vhpi; - // TODO: Add support for XENO - if ( VMX_VPD(vcpu,vac).a_int ) { - ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, - (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); - } -} - -#ifdef V_IOSAPIC_READY -void vlapic_update_shared_info(VCPU *vcpu) -{ - //int i; - - vl_apic_info *ps; - - if (vcpu->domain == dom0) - return; - - ps = get_psapic(vcpu); - ps->vl_lapic_id = ((VPD_CR(vcpu, lid) >> 16) & 0xffff) << 16; - printf("vl_lapic_id = %x\n", ps->vl_lapic_id); - ps->vl_apr = 0; - // skip ps->vl_logical_dest && ps->vl_dest_format - // IPF support physical destination mode only - ps->vl_arb_id = 0; - /* - for ( i=0; i<4; i++ ) { - ps->tmr[i] = 0; // edge trigger - } - */ -} - -void vlapic_update_ext_irq(VCPU *vcpu) -{ - int vec; - - vl_apic_info *ps = get_psapic(vcpu); - while ( (vec = highest_bits(ps->irr)) != NULL_VECTOR ) { - clear_bit (vec, ps->irr); - vmx_vcpu_pend_interrupt(vcpu, vec); - } -} -#endif - -void vlsapic_reset(VCPU *vcpu) -{ - int i; -#ifdef V_IOSAPIC_READY - vl_apic_info *psapic; // shared lapic inf. -#endif - - VPD_CR(vcpu, lid) = ia64_getreg(_IA64_REG_CR_LID); - VPD_CR(vcpu, ivr) = 0; - VPD_CR(vcpu,tpr) = 0x10000; - VPD_CR(vcpu, eoi) = 0; - VPD_CR(vcpu, irr[0]) = 0; - VPD_CR(vcpu, irr[1]) = 0; - VPD_CR(vcpu, irr[2]) = 0; - VPD_CR(vcpu, irr[3]) = 0; - VPD_CR(vcpu, pmv) = 0x10000; - VPD_CR(vcpu, cmcv) = 0x10000; - VPD_CR(vcpu, lrr0) = 0x10000; // default reset value? - VPD_CR(vcpu, lrr1) = 0x10000; // default reset value? - update_vhpi(vcpu, NULL_VECTOR); - for ( i=0; i<4; i++) { - VLSAPIC_INSVC(vcpu,i) = 0; - } -#ifdef V_IOSAPIC_READY - vlapic_update_shared_info(vcpu); - //vlapic_update_shared_irr(vcpu); -#endif - DPRINTK("VLSAPIC inservice base=%lp\n", &VLSAPIC_INSVC(vcpu,0) ); -} - -/* - * Find highest signaled bits in 4 words (long). - * - * return 0-255: highest bits. - * -1 : Not found. - */ -static __inline__ int highest_bits(uint64_t *dat) -{ - uint64_t bits, bitnum; - int i; - - /* loop for all 256 bits */ - for ( i=3; i >= 0 ; i -- ) { - bits = dat[i]; - if ( bits ) { - bitnum = ia64_fls(bits); - return i*64+bitnum; - } - } - return NULL_VECTOR; -} - -/* - * Return 0-255 for pending irq. - * NULL_VECTOR: when no pending. - */ -static int highest_pending_irq(VCPU *vcpu) -{ - if ( VPD_CR(vcpu, irr[0]) & (1UL<<NMI_VECTOR) ) return NMI_VECTOR; - if ( VPD_CR(vcpu, irr[0]) & (1UL<<ExtINT_VECTOR) ) return ExtINT_VECTOR; - return highest_bits(&VPD_CR(vcpu, irr[0])); -} - -static int highest_inservice_irq(VCPU *vcpu) -{ - if ( VLSAPIC_INSVC(vcpu, 0) & (1UL<<NMI_VECTOR) ) return NMI_VECTOR; - if ( VLSAPIC_INSVC(vcpu, 0) & (1UL<<ExtINT_VECTOR) ) return ExtINT_VECTOR; - return highest_bits(&(VLSAPIC_INSVC(vcpu, 0))); -} - -/* - * The pending irq is higher than the inservice one. - * - */ -static int is_higher_irq(int pending, int inservice) -{ - return ( (pending >> 4) > (inservice>>4) || - ((pending != NULL_VECTOR) && (inservice == NULL_VECTOR)) ); -} - -static int is_higher_class(int pending, int mic) -{ - return ( (pending >> 4) > mic ); -} - -static int is_invalid_irq(int vec) -{ - return (vec == 1 || ((vec <= 14 && vec >= 3))); -} - -#define IRQ_NO_MASKED 0 -#define IRQ_MASKED_BY_VTPR 1 -#define IRQ_MASKED_BY_INSVC 2 // masked by inservice IRQ - -/* See Table 5-8 in SDM vol2 for the definition */ -static int -_xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) -{ - tpr_t vtpr; - uint64_t mmi; - - vtpr.val = VPD_CR(vcpu, tpr); - - if ( h_inservice == NMI_VECTOR ) { - return IRQ_MASKED_BY_INSVC; - } - if ( h_pending == NMI_VECTOR ) { - // Non Maskable Interrupt - return IRQ_NO_MASKED; - } - if ( h_inservice == ExtINT_VECTOR ) { - return IRQ_MASKED_BY_INSVC; - } - mmi = vtpr.mmi; - if ( h_pending == ExtINT_VECTOR ) { - if ( mmi ) { - // mask all external IRQ - return IRQ_MASKED_BY_VTPR; - } - else { - return IRQ_NO_MASKED; - } - } - - if ( is_higher_irq(h_pending, h_inservice) ) { - if ( !mmi && is_higher_class(h_pending, vtpr.mic) ) { - return IRQ_NO_MASKED; - } - else { - return IRQ_MASKED_BY_VTPR; - } - } - else { - return IRQ_MASKED_BY_INSVC; - } -} - -static int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) -{ - int mask; - - mask = _xirq_masked(vcpu, h_pending, h_inservice); - return mask; -} - - -/* - * May come from virtualization fault or - * nested host interrupt. - */ -void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) -{ - uint64_t spsr; - - if (vector & ~0xff) { - DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n"); - return; - } - local_irq_save(spsr); - VPD_CR(vcpu,irr[vector>>6]) |= 1UL<<(vector&63); - //vlapic_update_shared_irr(vcpu); - local_irq_restore(spsr); - vcpu->arch.irq_new_pending = 1; -} - -/* - * 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) -{ - uint64_t spsr; - int i; - - local_irq_save(spsr); - for (i=0 ; i<4; i++ ) { - VPD_CR(vcpu,irr[i]) |= pend_irr[i]; - } - //vlapic_update_shared_irr(vcpu); - local_irq_restore(spsr); - vcpu->arch.irq_new_pending = 1; -} - -/* - * If the new pending interrupt is enabled and not masked, we directly inject - * it into the guest. Otherwise, we set the VHPI if vac.a_int=1 so that when - * the interrupt becomes unmasked, it gets injected. - * RETURN: - * TRUE: Interrupt is injected. - * FALSE: Not injected but may be in VHPI when vac.a_int=1 - * - * Optimization: We defer setting the VHPI until the EOI time, if a higher - * priority interrupt is in-service. The idea is to reduce the - * number of unnecessary calls to inject_vhpi. - */ -int vmx_check_pending_irq(VCPU *vcpu) -{ - uint64_t spsr, mask; - int h_pending, h_inservice; - int injected=0; - uint64_t isr; - IA64_PSR vpsr; - - local_irq_save(spsr); - h_pending = highest_pending_irq(vcpu); - if ( h_pending == NULL_VECTOR ) goto chk_irq_exit; - h_inservice = highest_inservice_irq(vcpu); - - vpsr.val = vmx_vcpu_get_psr(vcpu); - mask = irq_masked(vcpu, h_pending, h_inservice); - if ( vpsr.i && IRQ_NO_MASKED == mask ) { - isr = vpsr.val & IA64_PSR_RI; - if ( !vpsr.ic ) - panic("Interrupt when IC=0\n"); - vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ - injected = 1; - } - 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. - update_vhpi(vcpu,h_pending); - } - -chk_irq_exit: - local_irq_restore(spsr); - return injected; -} - -/* - * Only coming from virtualization fault. - */ -void guest_write_eoi(VCPU *vcpu) -{ - int vec; - uint64_t spsr; - - vec = highest_inservice_irq(vcpu); - if ( vec == NULL_VECTOR ) panic("Wrong vector to EOI\n"); - local_irq_save(spsr); - VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); - local_irq_restore(spsr); - VPD_CR(vcpu, eoi)=0; // overwrite the data - vmx_check_pending_irq(vcpu); -} - -uint64_t guest_read_vivr(VCPU *vcpu) -{ - int vec, next, h_inservice; - uint64_t spsr; - - local_irq_save(spsr); - 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); - return IA64_SPURIOUS_INT_VECTOR; - } - - VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63)); - VPD_CR(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63)); - update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write - //vlapic_update_shared_irr(vcpu); - local_irq_restore(spsr); - return (uint64_t)vec; -} - -static void generate_exirq(VCPU *vcpu) -{ - IA64_PSR vpsr; - uint64_t isr; - - vpsr.val = vmx_vcpu_get_psr(vcpu); - update_vhpi(vcpu, NULL_VECTOR); - isr = vpsr.val & IA64_PSR_RI; - if ( !vpsr.ic ) - panic("Interrupt when IC=0\n"); - vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ -} - -vhpi_detection(VCPU *vcpu) -{ - uint64_t threshold,vhpi; - tpr_t vtpr; - IA64_PSR vpsr; - - vpsr.val = vmx_vcpu_get_psr(vcpu); - vtpr.val = VPD_CR(vcpu, tpr); - - threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; - vhpi = VMX_VPD(vcpu,vhpi); - if ( vhpi > threshold ) { - // interrupt actived - generate_exirq (vcpu); - } -} - -vmx_vexirq(VCPU *vcpu) -{ - static uint64_t vexirq_count=0; - - vexirq_count ++; - printk("Virtual ex-irq %ld\n", vexirq_count); - generate_exirq (vcpu); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmmu.c --- a/xen/arch/ia64/vmmu.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,846 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmmu.c: virtual memory management unit components. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <asm/tlb.h> -#include <asm/gcc_intrin.h> -#include <asm/vcpu.h> -#include <linux/interrupt.h> -#include <asm/vmx_vcpu.h> -#include <asm/vmx_mm_def.h> -#include <asm/vmx.h> -#include <asm/hw_irq.h> -#include <asm/vmx_pal_vsa.h> -#include <asm/kregs.h> - -/* - * Architecture ppn is in 4KB unit while XEN - * page may be different(1<<PAGE_SHIFT). - */ -static inline u64 arch_ppn_to_xen_ppn(u64 appn) -{ - return (appn << ARCH_PAGE_SHIFT) >> PAGE_SHIFT; -} - -static inline u64 xen_ppn_to_arch_ppn(u64 xppn) -{ - return (xppn << PAGE_SHIFT) >> ARCH_PAGE_SHIFT; -} - - -/* - * Get the machine page frame number in 16KB unit - * Input: - * d: - */ -u64 get_mfn(domid_t domid, u64 gpfn, u64 pages) -{ - struct domain *d; - u64 i, xen_gppn, xen_mppn, mpfn; - - if ( domid == DOMID_SELF ) { - d = current->domain; - } - else { - d = find_domain_by_id(domid); - } - xen_gppn = arch_ppn_to_xen_ppn(gpfn); - xen_mppn = __gpfn_to_mfn(d, xen_gppn); -/* - for (i=0; i<pages; i++) { - if ( __gpfn_to_mfn(d, gpfn+i) == INVALID_MFN ) { - return INVALID_MFN; - } - } -*/ - mpfn= xen_ppn_to_arch_ppn(xen_mppn); - mpfn = mpfn | (((1UL <<(PAGE_SHIFT-12))-1)&gpfn); - return mpfn; - -} - -/* - * The VRN bits of va stand for which rr to get. - */ -ia64_rr vmmu_get_rr(VCPU *vcpu, u64 va) -{ - ia64_rr vrr; - vmx_vcpu_get_rr(vcpu, va, &vrr.rrval); - return vrr; -} - - -void recycle_message(thash_cb_t *hcb, u64 para) -{ - printk("hcb=%p recycled with %lx\n",hcb,para); -} - - -/* - * Purge all guest TCs in logical processor. - * Instead of purging all LP TCs, we should only purge - * TCs that belong to this guest. - */ -void -purge_machine_tc_by_domid(domid_t domid) -{ -#ifndef PURGE_GUEST_TC_ONLY - // purge all TCs - struct ia64_pal_retval result; - u64 addr; - u32 count1,count2; - u32 stride1,stride2; - u32 i,j; - u64 psr; - - - result = ia64_pal_call_static(PAL_PTCE_INFO,0,0,0, 0); - if ( result.status != 0 ) { - panic ("PAL_PTCE_INFO failed\n"); - } - addr = result.v0; - count1 = HIGH_32BITS(result.v1); - count2 = LOW_32BITS (result.v1); - stride1 = HIGH_32BITS(result.v2); - stride2 = LOW_32BITS (result.v2); - - local_irq_save(psr); - for (i=0; i<count1; i++) { - for (j=0; j<count2; j++) { - ia64_ptce(addr); - addr += stride2; - } - addr += stride1; - } - local_irq_restore(psr); -#else - // purge all TCs belong to this guest. -#endif -} - -static thash_cb_t *init_domain_vhpt(struct vcpu *d) -{ - struct pfn_info *page; - void *vbase,*vcur; - vhpt_special *vs; - thash_cb_t *vhpt; - PTA pta_value; - - page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); - if ( page == NULL ) { - panic("No enough contiguous memory for init_domain_mm\n"); - } - vbase = page_to_virt(page); - printk("Allocate domain vhpt at 0x%lx\n", (u64)vbase); - memset(vbase, 0, VCPU_TLB_SIZE); - vcur = (void*)((u64)vbase + VCPU_TLB_SIZE); - vhpt = --((thash_cb_t*)vcur); - vhpt->ht = THASH_VHPT; - vhpt->vcpu = d; - vhpt->hash_func = machine_thash; - vs = --((vhpt_special *)vcur); - - /* Setup guest pta */ - pta_value.val = 0; - pta_value.ve = 1; - pta_value.vf = 1; - pta_value.size = VCPU_TLB_SHIFT - 1; /* 2M */ - pta_value.base = ((u64)vbase) >> PTA_BASE_SHIFT; - d->arch.arch_vmx.mpta = pta_value.val; - - vhpt->vs = vs; - vhpt->vs->get_mfn = get_mfn; - vhpt->vs->tag_func = machine_ttag; - vhpt->hash = vbase; - vhpt->hash_sz = VCPU_TLB_SIZE/2; - vhpt->cch_buf = (u64)vbase + vhpt->hash_sz; - vhpt->cch_sz = (u64)vcur - (u64)vhpt->cch_buf; - vhpt->recycle_notifier = recycle_message; - thash_init(vhpt,VCPU_TLB_SHIFT-1); - return vhpt; -} - - -thash_cb_t *init_domain_tlb(struct vcpu *d) -{ - struct pfn_info *page; - void *vbase,*vcur; - tlb_special_t *ts; - thash_cb_t *tlb; - - page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); - if ( page == NULL ) { - panic("No enough contiguous memory for init_domain_mm\n"); - } - vbase = page_to_virt(page); - printk("Allocate domain tlb at 0x%lx\n", (u64)vbase); - memset(vbase, 0, VCPU_TLB_SIZE); - vcur = (void*)((u64)vbase + VCPU_TLB_SIZE); - tlb = --((thash_cb_t*)vcur); - tlb->ht = THASH_TLB; - tlb->vcpu = d; - ts = --((tlb_special_t *)vcur); - tlb->ts = ts; - tlb->ts->vhpt = init_domain_vhpt(d); - tlb->hash_func = machine_thash; - tlb->hash = vbase; - tlb->hash_sz = VCPU_TLB_SIZE/2; - tlb->cch_buf = (u64)vbase + tlb->hash_sz; - tlb->cch_sz = (u64)vcur - (u64)tlb->cch_buf; - tlb->recycle_notifier = recycle_message; - thash_init(tlb,VCPU_TLB_SHIFT-1); - return tlb; -} - -/* Allocate physical to machine mapping table for domN - * FIXME: Later this interface may be removed, if that table is provided - * by control panel. Dom0 has gpfn identical to mfn, which doesn't need - * this interface at all. - */ -void -alloc_pmt(struct domain *d) -{ - struct pfn_info *page; - - /* Only called once */ - ASSERT(d->arch.pmt); - - page = alloc_domheap_pages(NULL, get_order(d->max_pages), 0); - ASSERT(page); - - d->arch.pmt = page_to_virt(page); - memset(d->arch.pmt, 0x55, d->max_pages * 8); -} - -/* - * Insert guest TLB to machine TLB. - * data: In TLB format - */ -void machine_tlb_insert(struct vcpu *d, thash_data_t *tlb) -{ - u64 saved_itir, saved_ifa, saved_rr; - u64 pages; - thash_data_t mtlb; - ia64_rr vrr; - unsigned int cl = tlb->cl; - - mtlb.ifa = tlb->vadr; - mtlb.itir = tlb->itir & ~ITIR_RV_MASK; - vrr = vmmu_get_rr(d,mtlb.ifa); - //vmx_vcpu_get_rr(d, mtlb.ifa, &vrr.value); - pages = PSIZE(vrr.ps) >> PAGE_SHIFT; - mtlb.page_flags = tlb->page_flags & ~PAGE_FLAGS_RV_MASK; - mtlb.ppn = get_mfn(DOMID_SELF,tlb->ppn, pages); - if (mtlb.ppn == INVALID_MFN) - panic("Machine tlb insert with invalid mfn number.\n"); - - __asm __volatile("rsm psr.ic|psr.i;; srlz.i" ); - - saved_itir = ia64_getreg(_IA64_REG_CR_ITIR); - saved_ifa = ia64_getreg(_IA64_REG_CR_IFA); - saved_rr = ia64_get_rr(mtlb.ifa); - - ia64_setreg(_IA64_REG_CR_ITIR, mtlb.itir); - ia64_setreg(_IA64_REG_CR_IFA, mtlb.ifa); - /* Only access memory stack which is mapped by TR, - * after rr is switched. - */ - ia64_set_rr(mtlb.ifa, vmx_vrrtomrr(d, vrr.rrval)); - ia64_srlz_d(); - if ( cl == ISIDE_TLB ) { - ia64_itci(mtlb.page_flags); - ia64_srlz_i(); - } - else { - ia64_itcd(mtlb.page_flags); - ia64_srlz_d(); - } - ia64_set_rr(mtlb.ifa,saved_rr); - ia64_srlz_d(); - ia64_setreg(_IA64_REG_CR_IFA, saved_ifa); - ia64_setreg(_IA64_REG_CR_ITIR, saved_itir); - __asm __volatile("ssm psr.ic|psr.i;; srlz.i" ); -} - -u64 machine_thash(PTA pta, u64 va, u64 rid, u64 ps) -{ - u64 saved_pta, saved_rr0; - u64 hash_addr, tag; - unsigned long psr; - struct vcpu *v = current; - ia64_rr vrr; - - - saved_pta = ia64_getreg(_IA64_REG_CR_PTA); - saved_rr0 = ia64_get_rr(0); - vrr.rrval = saved_rr0; - vrr.rid = rid; - vrr.ps = ps; - - va = (va << 3) >> 3; // set VRN to 0. - // TODO: Set to enforce lazy mode - local_irq_save(psr); - ia64_setreg(_IA64_REG_CR_PTA, pta.val); - ia64_set_rr(0, vmx_vrrtomrr(v, vrr.rrval)); - ia64_srlz_d(); - - hash_addr = ia64_thash(va); - ia64_setreg(_IA64_REG_CR_PTA, saved_pta); - - ia64_set_rr(0, saved_rr0); - ia64_srlz_d(); - local_irq_restore(psr); - return hash_addr; -} - -u64 machine_ttag(PTA pta, u64 va, u64 rid, u64 ps) -{ - u64 saved_pta, saved_rr0; - u64 hash_addr, tag; - u64 psr; - struct vcpu *v = current; - ia64_rr vrr; - - // TODO: Set to enforce lazy mode - saved_pta = ia64_getreg(_IA64_REG_CR_PTA); - saved_rr0 = ia64_get_rr(0); - vrr.rrval = saved_rr0; - vrr.rid = rid; - vrr.ps = ps; - - va = (va << 3) >> 3; // set VRN to 0. - local_irq_save(psr); - ia64_setreg(_IA64_REG_CR_PTA, pta.val); - ia64_set_rr(0, vmx_vrrtomrr(v, vrr.rrval)); - ia64_srlz_d(); - - tag = ia64_ttag(va); - ia64_setreg(_IA64_REG_CR_PTA, saved_pta); - - ia64_set_rr(0, saved_rr0); - ia64_srlz_d(); - local_irq_restore(psr); - return tag; -} - -/* - * Purge machine tlb. - * INPUT - * rr: guest rr. - * va: only bits 0:60 is valid - * size: bits format (1<<size) for the address range to purge. - * - */ -void machine_tlb_purge(u64 rid, u64 va, u64 ps) -{ - u64 saved_rr0; - u64 psr; - ia64_rr vrr; - - va = (va << 3) >> 3; // set VRN to 0. - saved_rr0 = ia64_get_rr(0); - vrr.rrval = saved_rr0; - vrr.rid = rid; - vrr.ps = ps; - local_irq_save(psr); - ia64_set_rr( 0, vmx_vrrtomrr(current,vrr.rrval) ); - ia64_srlz_d(); - ia64_ptcl(va, ps << 2); - ia64_set_rr( 0, saved_rr0 ); - ia64_srlz_d(); - local_irq_restore(psr); -} - - -int vhpt_enabled(VCPU *vcpu, uint64_t vadr, vhpt_ref_t ref) -{ - ia64_rr vrr; - PTA vpta; - IA64_PSR vpsr; - - vpsr.val = vmx_vcpu_get_psr(vcpu); - vrr = vmx_vcpu_rr(vcpu, vadr); - vmx_vcpu_get_pta(vcpu,&vpta.val); - - if ( vrr.ve & vpta.ve ) { - switch ( ref ) { - case DATA_REF: - case NA_REF: - return vpsr.dt; - case INST_REF: - return vpsr.dt && vpsr.it && vpsr.ic; - case RSE_REF: - return vpsr.dt && vpsr.rt; - - } - } - return 0; -} - - -int unimplemented_gva(VCPU *vcpu,u64 vadr) -{ - int bit=vcpu->domain->arch.imp_va_msb; - u64 ladr =(vadr<<3)>>(3+bit); - if(!ladr||ladr==(1U<<(61-bit))-1){ - return 0; - }else{ - return 1; - } -} - - -/* - * Prefetch guest bundle code. - * INPUT: - * code: buffer pointer to hold the read data. - * num: number of dword (8byts) to read. - */ -int -fetch_code(VCPU *vcpu, u64 gip, u64 *code) -{ - u64 gpip; // guest physical IP - u64 mpa; - thash_data_t *tlb; - ia64_rr vrr; - u64 mfn; - - if ( !(VMX_VPD(vcpu, vpsr) & IA64_PSR_IT) ) { // I-side physical mode - gpip = gip; - } - else { - vmx_vcpu_get_rr(vcpu, gip, &vrr.rrval); - tlb = vtlb_lookup_ex (vmx_vcpu_get_vtlb(vcpu), - vrr.rid, gip, ISIDE_TLB ); - if ( tlb == NULL ) panic("No entry found in ITLB\n"); - gpip = (tlb->ppn << 12) | ( gip & (PSIZE(tlb->ps)-1) ); - } - mfn = __gpfn_to_mfn(vcpu->domain, gpip >>PAGE_SHIFT); - if ( mfn == INVALID_MFN ) return 0; - - mpa = (gpip & (PAGE_SIZE-1)) | (mfn<<PAGE_SHIFT); - *code = *(u64*)__va(mpa); - return 1; -} - -IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) -{ - - thash_data_t data, *ovl; - thash_cb_t *hcb; - search_section_t sections; - ia64_rr vrr; - - hcb = vmx_vcpu_get_vtlb(vcpu); - data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; - data.itir=itir; - data.vadr=PAGEALIGN(ifa,data.ps); - data.tc = 1; - data.cl=ISIDE_TLB; - vmx_vcpu_get_rr(vcpu, ifa, &vrr); - data.rid = vrr.rid; - - sections.tr = 1; - sections.tc = 0; - - ovl = thash_find_overlap(hcb, &data, sections); - while (ovl) { - // generate MCA. - panic("Tlb conflict!!"); - return; - } - thash_purge_and_insert(hcb, &data); - return IA64_NO_FAULT; -} - - - - -IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) -{ - - thash_data_t data, *ovl; - thash_cb_t *hcb; - search_section_t sections; - ia64_rr vrr; - - hcb = vmx_vcpu_get_vtlb(vcpu); - data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; - data.itir=itir; - data.vadr=PAGEALIGN(ifa,data.ps); - data.tc = 1; - data.cl=DSIDE_TLB; - vmx_vcpu_get_rr(vcpu, ifa, &vrr); - data.rid = vrr.rid; - sections.tr = 1; - sections.tc = 0; - - ovl = thash_find_overlap(hcb, &data, sections); - if (ovl) { - // generate MCA. - panic("Tlb conflict!!"); - return; - } - thash_purge_and_insert(hcb, &data); - return IA64_NO_FAULT; -} - -/* - * Return TRUE/FALSE for success of lock operation - */ -int vmx_lock_guest_dtc (VCPU *vcpu, UINT64 va, int lock) -{ - - thash_cb_t *hcb; - ia64_rr vrr; - u64 preferred_size; - - vmx_vcpu_get_rr(vcpu, va, &vrr); - hcb = vmx_vcpu_get_vtlb(vcpu); - va = PAGEALIGN(va,vrr.ps); - preferred_size = PSIZE(vrr.ps); - return thash_lock_tc(hcb, va, preferred_size, vrr.rid, DSIDE_TLB, lock); -} - -IA64FAULT vmx_vcpu_itr_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa, UINT64 idx) -{ - - thash_data_t data, *ovl; - thash_cb_t *hcb; - search_section_t sections; - ia64_rr vrr; - - hcb = vmx_vcpu_get_vtlb(vcpu); - data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; - data.itir=itir; - data.vadr=PAGEALIGN(ifa,data.ps); - data.tc = 0; - data.cl=ISIDE_TLB; - vmx_vcpu_get_rr(vcpu, ifa, &vrr); - data.rid = vrr.rid; - sections.tr = 1; - sections.tc = 0; - - ovl = thash_find_overlap(hcb, &data, sections); - if (ovl) { - // generate MCA. - panic("Tlb conflict!!"); - return; - } - sections.tr = 0; - sections.tc = 1; - thash_purge_entries(hcb, &data, sections); - thash_tr_insert(hcb, &data, ifa, idx); - return IA64_NO_FAULT; -} - -IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa, UINT64 idx) -{ - - thash_data_t data, *ovl; - thash_cb_t *hcb; - search_section_t sections; - ia64_rr vrr; - - - hcb = vmx_vcpu_get_vtlb(vcpu); - data.page_flags=pte & ~PAGE_FLAGS_RV_MASK; - data.itir=itir; - data.vadr=PAGEALIGN(ifa,data.ps); - data.tc = 0; - data.cl=DSIDE_TLB; - vmx_vcpu_get_rr(vcpu, ifa, &vrr); - data.rid = vrr.rid; - sections.tr = 1; - sections.tc = 0; - - ovl = thash_find_overlap(hcb, &data, sections); - while (ovl) { - // generate MCA. - panic("Tlb conflict!!"); - return; - } - sections.tr = 0; - sections.tc = 1; - thash_purge_entries(hcb, &data, sections); - thash_tr_insert(hcb, &data, ifa, idx); - return IA64_NO_FAULT; -} - - - -IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 ps) -{ - thash_cb_t *hcb; - ia64_rr rr; - search_section_t sections; - - hcb = vmx_vcpu_get_vtlb(vcpu); - rr=vmx_vcpu_rr(vcpu,vadr); - sections.tr = 1; - sections.tc = 1; - thash_purge_entries_ex(hcb,rr.rid,vadr,ps,sections,DSIDE_TLB); - return IA64_NO_FAULT; -} - -IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 ps) -{ - thash_cb_t *hcb; - ia64_rr rr; - search_section_t sections; - hcb = vmx_vcpu_get_vtlb(vcpu); - rr=vmx_vcpu_rr(vcpu,vadr); - sections.tr = 1; - sections.tc = 1; - thash_purge_entries_ex(hcb,rr.rid,vadr,ps,sections,ISIDE_TLB); - return IA64_NO_FAULT; -} - -IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 ps) -{ - thash_cb_t *hcb; - ia64_rr vrr; - search_section_t sections; - thash_data_t data, *ovl; - hcb = vmx_vcpu_get_vtlb(vcpu); - vrr=vmx_vcpu_rr(vcpu,vadr); - sections.tr = 0; - sections.tc = 1; - vadr = PAGEALIGN(vadr, ps); - - thash_purge_entries_ex(hcb,vrr.rid,vadr,ps,sections,DSIDE_TLB); - thash_purge_entries_ex(hcb,vrr.rid,vadr,ps,sections,ISIDE_TLB); - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) -{ - thash_cb_t *hcb; - hcb = vmx_vcpu_get_vtlb(vcpu); - thash_purge_all(hcb); - return IA64_NO_FAULT; -} - -IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 ps) -{ - vmx_vcpu_ptc_l(vcpu, vadr, ps); - return IA64_ILLOP_FAULT; -} - -IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 ps) -{ - vmx_vcpu_ptc_l(vcpu, vadr, ps); - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval) -{ - PTA vpta; - ia64_rr vrr; - u64 vhpt_offset,tmp; - vmx_vcpu_get_pta(vcpu, &vpta.val); - vrr=vmx_vcpu_rr(vcpu, vadr); - if(vpta.vf){ - panic("THASH,Don't support long format VHPT"); - *pval = ia64_call_vsa(PAL_VPS_THASH,vadr,vrr.rrval,vpta.val,0,0,0,0); - }else{ - vhpt_offset=((vadr>>vrr.ps)<<3)&((1UL<<(vpta.size))-1); - *pval = (vadr&VRN_MASK)| - (vpta.val<<3>>(vpta.size+3)<<(vpta.size))| - vhpt_offset; - } - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval) -{ - ia64_rr vrr; - PTA vpta; - vmx_vcpu_get_pta(vcpu, &vpta.val); - vrr=vmx_vcpu_rr(vcpu, vadr); - if(vpta.vf){ - panic("THASH,Don't support long format VHPT"); - *pval = ia64_call_vsa(PAL_VPS_TTAG,vadr,vrr.rrval,0,0,0,0,0); - }else{ - *pval = 1; - } - return IA64_NO_FAULT; -} - - - -IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) -{ - thash_data_t *data; - thash_cb_t *hcb; - ia64_rr vrr; - ISR visr,pt_isr; - REGS *regs; - u64 vhpt_adr; - IA64_PSR vpsr; - hcb = vmx_vcpu_get_vtlb(vcpu); - vrr=vmx_vcpu_rr(vcpu,vadr); - regs=vcpu_regs(vcpu); - pt_isr.val=regs->cr_isr; - visr.val=0; - visr.ei=pt_isr.ei; - visr.ir=pt_isr.ir; - vpsr.val = vmx_vcpu_get_psr(vcpu); - if(vpsr.ic==0){ - visr.ni=1; - } - visr.na=1; - data = vtlb_lookup_ex(hcb, vrr.rid, vadr, DSIDE_TLB); - if(data){ - if(data->p==0){ - visr.na=1; - vmx_vcpu_set_isr(vcpu,visr.val); - page_not_present(vcpu, vadr); - return IA64_FAULT; - }else if(data->ma == VA_MATTR_NATPAGE){ - visr.na = 1; - vmx_vcpu_set_isr(vcpu, visr.val); - dnat_page_consumption(vcpu, vadr); - return IA64_FAULT; - }else{ - *padr = (data->ppn<<12) | (vadr&(PSIZE(data->ps)-1)); - return IA64_NO_FAULT; - } - }else{ - if(!vhpt_enabled(vcpu, vadr, NA_REF)){ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, visr.val); - alt_dtlb(vcpu, vadr); - return IA64_FAULT; - } - else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - else{ - vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); - vrr=vmx_vcpu_rr(vcpu,vhpt_adr); - data = vtlb_lookup_ex(hcb, vrr.rid, vhpt_adr, DSIDE_TLB); - if(data){ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, visr.val); - dtlb_fault(vcpu, vadr); - return IA64_FAULT; - } - else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - else{ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, visr.val); - dvhpt_fault(vcpu, vadr); - return IA64_FAULT; - } - else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - } - } -} - -IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) -{ - thash_data_t *data; - thash_cb_t *hcb; - ia64_rr rr; - PTA vpta; - vmx_vcpu_get_pta(vcpu, &vpta.val); - if(vpta.vf==0 || unimplemented_gva(vcpu, vadr)){ - *key=1; - return IA64_NO_FAULT; - } - hcb = vmx_vcpu_get_vtlb(vcpu); - rr=vmx_vcpu_rr(vcpu,vadr); - data = vtlb_lookup_ex(hcb, rr.rid, vadr, DSIDE_TLB); - if(!data||!data->p){ - *key=1; - }else{ - *key=data->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; - thash_cb_t *vtlb; - unsigned long end; /* end of the area mapped by current entry */ - thash_data_t *entry; - struct vcpu *v = current; - ia64_rr vrr; - - vtlb = vmx_vcpu_get_vtlb(v); - vrr = vmx_vcpu_rr(v, va); - entry = vtlb_lookup_ex(vtlb, vrr.rid, 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 = __gpfn_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 -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_entry.S --- a/xen/arch/ia64/vmx_entry.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,611 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_entry.S: - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) - * Kun Tian (Kevin Tian) (kevin.tian@xxxxxxxxx) - */ - -#ifndef VCPU_TLB_SHIFT -#define VCPU_TLB_SHIFT 22 -#endif -#include <linux/config.h> -#include <asm/asmmacro.h> -#include <asm/cache.h> -#include <asm/kregs.h> -#include <asm/offsets.h> -#include <asm/pgtable.h> -#include <asm/percpu.h> -#include <asm/processor.h> -#include <asm/thread_info.h> -#include <asm/unistd.h> - -#include "vmx_minstate.h" - -/* - * prev_task <- vmx_ia64_switch_to(struct task_struct *next) - * With Ingo's new scheduler, interrupts are disabled when this routine gets - * called. The code starting at .map relies on this. The rest of the code - * doesn't care about the interrupt masking status. - * - * Since we allocate domain stack in xenheap, there's no need to map new - * domain's stack since all xenheap is mapped by TR. Another different task - * for vmx_ia64_switch_to is to switch to bank0 and change current pointer. - */ -GLOBAL_ENTRY(vmx_ia64_switch_to) - .prologue - alloc r16=ar.pfs,1,0,0,0 - DO_SAVE_SWITCH_STACK - .body - - bsw.0 // Switch to bank0, because bank0 r21 is current pointer - ;; - adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 - movl r25=init_task - adds r26=IA64_TASK_THREAD_KSP_OFFSET,in0 - ;; - st8 [r22]=sp // save kernel stack pointer of old task - ;; - /* - * TR always mapped this task's page, we can skip doing it again. - */ - ld8 sp=[r26] // load kernel stack pointer of new task - mov r21=in0 // update "current" application register - mov r8=r13 // return pointer to previously running task - mov r13=in0 // set "current" pointer - ;; - bsw.1 - ;; - DO_LOAD_SWITCH_STACK - -#ifdef CONFIG_SMP - sync.i // ensure "fc"s done by this CPU are visible on other CPUs -#endif - br.ret.sptk.many rp // boogie on out in new context -END(vmx_ia64_switch_to) - -GLOBAL_ENTRY(ia64_leave_nested) - rsm psr.i - ;; - adds r21=PT(PR)+16,r12 - ;; - - lfetch [r21],PT(CR_IPSR)-PT(PR) - adds r2=PT(B6)+16,r12 - adds r3=PT(R16)+16,r12 - ;; - lfetch [r21] - ld8 r28=[r2],8 // load b6 - adds r29=PT(R24)+16,r12 - - ld8.fill r16=[r3] - adds r3=PT(AR_CSD)-PT(R16),r3 - adds r30=PT(AR_CCV)+16,r12 - ;; - ld8.fill r24=[r29] - ld8 r15=[r30] // load ar.ccv - ;; - ld8 r29=[r2],16 // load b7 - ld8 r30=[r3],16 // load ar.csd - ;; - ld8 r31=[r2],16 // load ar.ssd - ld8.fill r8=[r3],16 - ;; - ld8.fill r9=[r2],16 - ld8.fill r10=[r3],PT(R17)-PT(R10) - ;; - ld8.fill r11=[r2],PT(R18)-PT(R11) - ld8.fill r17=[r3],16 - ;; - ld8.fill r18=[r2],16 - ld8.fill r19=[r3],16 - ;; - ld8.fill r20=[r2],16 - ld8.fill r21=[r3],16 - mov ar.csd=r30 - mov ar.ssd=r31 - ;; - rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection - invala // invalidate ALAT - ;; - ld8.fill r22=[r2],24 - ld8.fill r23=[r3],24 - mov b6=r28 - ;; - ld8.fill r25=[r2],16 - ld8.fill r26=[r3],16 - mov b7=r29 - ;; - ld8.fill r27=[r2],16 - ld8.fill r28=[r3],16 - ;; - ld8.fill r29=[r2],16 - ld8.fill r30=[r3],24 - ;; - ld8.fill r31=[r2],PT(F9)-PT(R31) - adds r3=PT(F10)-PT(F6),r3 - ;; - ldf.fill f9=[r2],PT(F6)-PT(F9) - ldf.fill f10=[r3],PT(F8)-PT(F10) - ;; - ldf.fill f6=[r2],PT(F7)-PT(F6) - ;; - ldf.fill f7=[r2],PT(F11)-PT(F7) - ldf.fill f8=[r3],32 - ;; - srlz.i // ensure interruption collection is off - mov ar.ccv=r15 - ;; - bsw.0 // switch back to bank 0 (no stop bit required beforehand...) - ;; - ldf.fill f11=[r2] -// mov r18=r13 -// mov r21=r13 - adds r16=PT(CR_IPSR)+16,r12 - adds r17=PT(CR_IIP)+16,r12 - ;; - ld8 r29=[r16],16 // load cr.ipsr - ld8 r28=[r17],16 // load cr.iip - ;; - ld8 r30=[r16],16 // load cr.ifs - ld8 r25=[r17],16 // load ar.unat - ;; - ld8 r26=[r16],16 // load ar.pfs - ld8 r27=[r17],16 // load ar.rsc - cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs - ;; - ld8 r24=[r16],16 // load ar.rnat (may be garbage) - ld8 r23=[r17],16// load ar.bspstore (may be garbage) - ;; - ld8 r31=[r16],16 // load predicates - ld8 r22=[r17],16 // load b0 - ;; - ld8 r19=[r16],16 // load ar.rsc value for "loadrs" - ld8.fill r1=[r17],16 // load r1 - ;; - ld8.fill r12=[r16],16 - ld8.fill r13=[r17],16 - ;; - ld8 r20=[r16],16 // ar.fpsr - ld8.fill r15=[r17],16 - ;; - ld8.fill r14=[r16],16 - ld8.fill r2=[r17] - ;; - ld8.fill r3=[r16] - ;; - mov r16=ar.bsp // get existing backing store pointer - ;; - mov b0=r22 - mov ar.pfs=r26 - mov cr.ifs=r30 - mov cr.ipsr=r29 - mov ar.fpsr=r20 - mov cr.iip=r28 - ;; - mov ar.rsc=r27 - mov ar.unat=r25 - mov pr=r31,-1 - rfi -END(ia64_leave_nested) - - - -GLOBAL_ENTRY(ia64_leave_hypervisor) - PT_REGS_UNWIND_INFO(0) - /* - * work.need_resched etc. mustn't get changed by this CPU before it returns to - ;; - * user- or fsys-mode, hence we disable interrupts early on: - */ - rsm psr.i - ;; - alloc loc0=ar.pfs,0,1,1,0 - adds out0=16,r12 - ;; - br.call.sptk.many b0=leave_hypervisor_tail - mov ar.pfs=loc0 - adds r8=IA64_VPD_BASE_OFFSET,r13 - ;; - ld8 r8=[r8] - ;; - adds r9=VPD(VPSR),r8 - ;; - ld8 r9=[r9] - ;; - tbit.z pBN0,pBN1=r9,IA64_PSR_BN_BIT - ;; -(pBN0) add r7=VPD(VBNAT),r8; -(pBN1) add r7=VPD(VNAT),r8; - ;; - ld8 r7=[r7] - ;; - mov ar.unat=r7 -(pBN0) add r4=VPD(VBGR),r8; -(pBN1) add r4=VPD(VGR),r8; -(pBN0) add r5=VPD(VBGR)+0x8,r8; -(pBN1) add r5=VPD(VGR)+0x8,r8; - ;; - ld8.fill r16=[r4],16 - ld8.fill r17=[r5],16 - ;; - ld8.fill r18=[r4],16 - ld8.fill r19=[r5],16 - ;; - ld8.fill r20=[r4],16 - ld8.fill r21=[r5],16 - ;; - ld8.fill r22=[r4],16 - ld8.fill r23=[r5],16 - ;; - ld8.fill r24=[r4],16 - ld8.fill r25=[r5],16 - ;; - ld8.fill r26=[r4],16 - ld8.fill r27=[r5],16 - ;; - ld8.fill r28=[r4],16 - ld8.fill r29=[r5],16 - ;; - ld8.fill r30=[r4],16 - ld8.fill r31=[r5],16 - ;; - bsw.0 - ;; - mov r18=r8 //vpd - mov r19=r9 //vpsr - adds r20=PT(PR)+16,r12 - ;; - lfetch [r20],PT(CR_IPSR)-PT(PR) - adds r16=PT(B6)+16,r12 - adds r17=PT(B7)+16,r12 - ;; - lfetch [r20] - mov r21=r13 // get current - ;; - ld8 r30=[r16],16 // load b6 - ld8 r31=[r17],16 // load b7 - add r20=PT(EML_UNAT)+16,r12 - ;; - ld8 r29=[r20] //load ar_unat - mov b6=r30 - mov b7=r31 - ld8 r30=[r16],16 //load ar_csd - ld8 r31=[r17],16 //load ar_ssd - ;; - mov ar.unat=r29 - mov ar.csd=r30 - mov ar.ssd=r31 - ;; - ld8.fill r8=[r16],16 //load r8 - ld8.fill r9=[r17],16 //load r9 - ;; - ld8.fill r10=[r16],PT(R1)-PT(R10) //load r10 - ld8.fill r11=[r17],PT(R12)-PT(R11) //load r11 - ;; - ld8.fill r1=[r16],16 //load r1 - ld8.fill r12=[r17],16 //load r12 - ;; - ld8.fill r13=[r16],16 //load r13 - ld8 r30=[r17],16 //load ar_fpsr - ;; - ld8.fill r15=[r16],16 //load r15 - ld8.fill r14=[r17],16 //load r14 - mov ar.fpsr=r30 - ;; - ld8.fill r2=[r16],16 //load r2 - ld8.fill r3=[r17],16 //load r3 - ;; -/* -(pEml) ld8.fill r4=[r16],16 //load r4 -(pEml) ld8.fill r5=[r17],16 //load r5 - ;; -(pEml) ld8.fill r6=[r16],PT(AR_CCV)-PT(R6) //load r6 -(pEml) ld8.fill r7=[r17],PT(F7)-PT(R7) //load r7 - ;; -(pNonEml) adds r16=PT(AR_CCV)-PT(R4),r16 -(pNonEml) adds r17=PT(F7)-PT(R5),r17 - ;; -*/ - ld8.fill r4=[r16],16 //load r4 - ld8.fill r5=[r17],16 //load r5 - ;; - ld8.fill r6=[r16],PT(AR_CCV)-PT(R6) //load r6 - ld8.fill r7=[r17],PT(F7)-PT(R7) //load r7 - ;; - - ld8 r30=[r16],PT(F6)-PT(AR_CCV) - rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection - ;; - srlz.i // ensure interruption collection is off - ;; - invala // invalidate ALAT - ;; - ldf.fill f6=[r16],32 - ldf.fill f7=[r17],32 - ;; - ldf.fill f8=[r16],32 - ldf.fill f9=[r17],32 - ;; - ldf.fill f10=[r16] - ldf.fill f11=[r17] - ;; - mov ar.ccv=r30 - adds r16=PT(CR_IPSR)-PT(F10),r16 - adds r17=PT(CR_IIP)-PT(F11),r17 - ;; - ld8 r31=[r16],16 // load cr.ipsr - ld8 r30=[r17],16 // load cr.iip - ;; - ld8 r29=[r16],16 // load cr.ifs - ld8 r28=[r17],16 // load ar.unat - ;; - ld8 r27=[r16],16 // load ar.pfs - ld8 r26=[r17],16 // load ar.rsc - ;; - ld8 r25=[r16],16 // load ar.rnat (may be garbage) - ld8 r24=[r17],16// load ar.bspstore (may be garbage) - ;; - ld8 r23=[r16],16 // load predicates - ld8 r22=[r17],PT(RFI_PFS)-PT(B0) // load b0 - ;; - ld8 r20=[r16],16 // load ar.rsc value for "loadrs" - ;; -//rbs_switch - // loadrs has already been shifted - alloc r16=ar.pfs,0,0,0,0 // drop current register frame - ;; - mov ar.rsc=r20 - ;; - loadrs - ;; - mov ar.bspstore=r24 - ;; - ld8 r24=[r17] //load rfi_pfs - mov ar.unat=r28 - mov ar.rnat=r25 - mov ar.rsc=r26 - ;; - mov cr.ipsr=r31 - mov cr.iip=r30 - mov cr.ifs=r29 - cmp.ne p6,p0=r24,r0 -(p6)br.sptk vmx_dorfirfi - ;; -vmx_dorfirfi_back: - mov ar.pfs=r27 - -//vsa_sync_write_start - movl r20=__vsa_base - ;; - ld8 r20=[r20] // read entry point - mov r25=r18 - ;; - add r16=PAL_VPS_SYNC_WRITE,r20 - movl r24=switch_rr7 // calculate return address - ;; - mov b0=r16 - br.cond.sptk b0 // call the service - ;; -// switch rr7 and rr5 -switch_rr7: - adds r24=SWITCH_MRR5_OFFSET, r21 - adds r26=SWITCH_MRR6_OFFSET, r21 - adds r16=SWITCH_MRR7_OFFSET ,r21 - movl r25=(5<<61) - movl r27=(6<<61) - movl r17=(7<<61) - ;; - ld8 r24=[r24] - ld8 r26=[r26] - ld8 r16=[r16] - ;; - mov rr[r25]=r24 - mov rr[r27]=r26 - mov rr[r17]=r16 - ;; - srlz.i - ;; - add r24=SWITCH_MPTA_OFFSET, r21 - ;; - ld8 r24=[r24] - ;; - mov cr.pta=r24 - ;; - srlz.i - ;; -// fall through -GLOBAL_ENTRY(ia64_vmm_entry) -/* - * must be at bank 0 - * parameter: - * r18:vpd - * r19:vpsr - * r20:__vsa_base - * r22:b0 - * r23:predicate - */ - mov r24=r22 - mov r25=r18 - tbit.nz p1,p2 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic - ;; - (p1) add r29=PAL_VPS_RESUME_NORMAL,r20 - (p2) add r29=PAL_VPS_RESUME_HANDLER,r20 - ;; - mov pr=r23,-2 - mov b0=r29 - ;; - br.cond.sptk b0 // call pal service -END(ia64_leave_hypervisor) - -//r24 rfi_pfs -//r17 address of rfi_pfs -GLOBAL_ENTRY(vmx_dorfirfi) - mov r16=ar.ec - movl r20 = vmx_dorfirfi_back - ;; -// clean rfi_pfs - st8 [r17]=r0 - mov b0=r20 -// pfs.pec=ar.ec - dep r24 = r16, r24, 52, 6 - ;; - mov ar.pfs=r24 - ;; - br.ret.sptk b0 - ;; -END(vmx_dorfirfi) - - -#define VMX_PURGE_RR7 0 -#define VMX_INSERT_RR7 1 -/* - * in0: old rr7 - * in1: virtual address of xen image - * in2: virtual address of vhpt table - */ -GLOBAL_ENTRY(vmx_purge_double_mapping) - alloc loc1 = ar.pfs,5,9,0,0 - mov loc0 = rp - movl r8 = 1f - ;; - movl loc4 = KERNEL_TR_PAGE_SHIFT - movl loc5 = VCPU_TLB_SHIFT - mov loc6 = psr - movl loc7 = XEN_RR7_SWITCH_STUB - mov loc8 = (1<<VMX_PURGE_RR7) - ;; - srlz.i - ;; - rsm psr.i | psr.ic - ;; - srlz.i - ;; - mov ar.rsc = 0 - mov b6 = loc7 - mov rp = r8 - ;; - br.sptk b6 -1: - mov ar.rsc = 3 - mov rp = loc0 - ;; - mov psr.l = loc6 - ;; - srlz.i - ;; - br.ret.sptk rp -END(vmx_purge_double_mapping) - -/* - * in0: new rr7 - * in1: virtual address of xen image - * in2: virtual address of vhpt table - * in3: pte entry of xen image - * in4: pte entry of vhpt table - */ -GLOBAL_ENTRY(vmx_insert_double_mapping) - alloc loc1 = ar.pfs,5,9,0,0 - mov loc0 = rp - movl loc2 = IA64_TR_XEN_IN_DOM // TR number for xen image - ;; - movl loc3 = IA64_TR_VHPT_IN_DOM // TR number for vhpt table - movl r8 = 1f - movl loc4 = KERNEL_TR_PAGE_SHIFT - ;; - movl loc5 = VCPU_TLB_SHIFT - mov loc6 = psr - movl loc7 = XEN_RR7_SWITCH_STUB - ;; - srlz.i - ;; - rsm psr.i | psr.ic - mov loc8 = (1<<VMX_INSERT_RR7) - ;; - srlz.i - ;; - mov ar.rsc = 0 - mov b6 = loc7 - mov rp = r8 - ;; - br.sptk b6 -1: - mov ar.rsc = 3 - mov rp = loc0 - ;; - mov psr.l = loc6 - ;; - srlz.i - ;; - br.ret.sptk rp -END(vmx_insert_double_mapping) - - .align PAGE_SIZE -/* - * Stub to add double mapping for new domain, which shouldn't - * access any memory when active. Before reaching this point, - * both psr.i/ic is cleared and rse is set in lazy mode. - * - * in0: new rr7 - * in1: virtual address of xen image - * in2: virtual address of vhpt table - * in3: pte entry of xen image - * in4: pte entry of vhpt table - * loc2: TR number for xen image - * loc3: TR number for vhpt table - * loc4: page size for xen image - * loc5: page size of vhpt table - * loc7: free to use - * loc8: purge or insert - * r8: will contain old rid value - */ -GLOBAL_ENTRY(vmx_switch_rr7) - movl loc7 = (7<<61) - dep.z loc4 = loc4, 2, 6 - dep.z loc5 = loc5, 2, 6 - ;; - tbit.nz p6,p7=loc8, VMX_INSERT_RR7 - mov r8 = rr[loc7] - ;; - mov rr[loc7] = in0 -(p6)mov cr.ifa = in1 -(p6)mov cr.itir = loc4 - ;; - srlz.i - ;; -(p6)itr.i itr[loc2] = in3 -(p7)ptr.i in1, loc4 - ;; -(p6)itr.d dtr[loc2] = in3 -(p7)ptr.d in1, loc4 - ;; - srlz.i - ;; -(p6)mov cr.ifa = in2 -(p6)mov cr.itir = loc5 - ;; -(p6)itr.d dtr[loc3] = in4 -(p7)ptr.d in2, loc5 - ;; - srlz.i - ;; - mov rr[loc7] = r8 - ;; - srlz.i - br.sptk rp -END(vmx_switch_rr7) - .align PAGE_SIZE diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_hypercall.c --- a/xen/arch/ia64/vmx_hypercall.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,235 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_hyparcall.c: handling hypercall from domain - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <xen/config.h> -#include <xen/errno.h> -#include <asm/vmx_vcpu.h> -#include <public/xen.h> -#include <public/event_channel.h> -#include <asm/vmmu.h> -#include <asm/tlb.h> -#include <asm/regionreg.h> -#include <asm/page.h> -#include <xen/mm.h> -#include <xen/multicall.h> - - -void hyper_not_support(void) -{ - VCPU *vcpu=current; - vmx_vcpu_set_gr(vcpu, 8, -1, 0); - vmx_vcpu_increment_iip(vcpu); -} - -void hyper_mmu_update(void) -{ - VCPU *vcpu=current; - u64 r32,r33,r34,r35,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - vmx_vcpu_get_gr(vcpu,17,&r33); - vmx_vcpu_get_gr(vcpu,18,&r34); - vmx_vcpu_get_gr(vcpu,19,&r35); - ret=do_mmu_update((mmu_update_t*)r32,r33,r34,r35); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - vmx_vcpu_increment_iip(vcpu); -} - -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...) -{ - struct mc_state *mcs = &mc_state[smp_processor_id()]; - VCPU *vcpu = current; - struct cpu_user_regs *regs = vcpu_regs(vcpu); - unsigned int i; - va_list args; - - va_start(args, nr_args); - if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { - panic("PREEMPT happen in multicall\n"); // Not support yet - } else { - vmx_vcpu_set_gr(vcpu, 15, op, 0); - for ( i = 0; i < nr_args; i++) { - switch (i) { - case 0: vmx_vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0); - break; - case 1: vmx_vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0); - break; - case 2: vmx_vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0); - break; - case 3: vmx_vcpu_set_gr(vcpu, 19, va_arg(args, unsigned long), 0); - break; - case 4: vmx_vcpu_set_gr(vcpu, 20, va_arg(args, unsigned long), 0); - break; - default: panic("Too many args for hypercall continuation\n"); - break; - } - } - } - vcpu->arch.hypercall_continuation = 1; - va_end(args); - return op; -} - -void hyper_dom_mem_op(void) -{ - VCPU *vcpu=current; - u64 r32,r33,r34,r35,r36; - u64 ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - vmx_vcpu_get_gr(vcpu,17,&r33); - vmx_vcpu_get_gr(vcpu,18,&r34); - vmx_vcpu_get_gr(vcpu,19,&r35); - vmx_vcpu_get_gr(vcpu,20,&r36); - ret=do_dom_mem_op(r32,(u64 *)r33,r34,r35,r36); - printf("do_dom_mem return value: %lx\n", ret); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - - /* Hard to define a special return value to indicate hypercall restart. - * So just add a new mark, which is SMP safe - */ - if (vcpu->arch.hypercall_continuation == 1) - vcpu->arch.hypercall_continuation = 0; - else - vmx_vcpu_increment_iip(vcpu); -} - - -void hyper_sched_op(void) -{ - VCPU *vcpu=current; - u64 r32,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - ret=do_sched_op(r32); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - - vmx_vcpu_increment_iip(vcpu); -} - -void hyper_dom0_op(void) -{ - VCPU *vcpu=current; - u64 r32,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - ret=do_dom0_op((dom0_op_t *)r32); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - - vmx_vcpu_increment_iip(vcpu); -} - -void hyper_event_channel_op(void) -{ - VCPU *vcpu=current; - u64 r32,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - ret=do_event_channel_op((evtchn_op_t *)r32); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - vmx_vcpu_increment_iip(vcpu); -} - -void hyper_xen_version(void) -{ - VCPU *vcpu=current; - u64 r32,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - ret=do_xen_version((int )r32); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - vmx_vcpu_increment_iip(vcpu); -} - -static int do_lock_page(VCPU *vcpu, u64 va, u64 lock) -{ - int i; - ia64_rr rr; - thash_cb_t *hcb; - hcb = vmx_vcpu_get_vtlb(vcpu); - rr = vmx_vcpu_rr(vcpu, va); - return thash_lock_tc(hcb, va ,1U<<rr.ps, rr.rid, DSIDE_TLB, lock); -} - -/* - * Lock guest page in vTLB, so that it's not relinquished by recycle - * session when HV is servicing that hypercall. - */ -void hyper_lock_page(void) -{ -//TODO: - VCPU *vcpu=current; - u64 va,lock, ret; - vmx_vcpu_get_gr(vcpu,16,&va); - vmx_vcpu_get_gr(vcpu,17,&lock); - ret=do_lock_page(vcpu, va, lock); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - - vmx_vcpu_increment_iip(vcpu); -} - -static int do_set_shared_page(VCPU *vcpu, u64 gpa) -{ - u64 shared_info, o_info; - struct domain *d = vcpu->domain; - struct vcpu *v; - if(vcpu->domain!=dom0) - return -EPERM; - shared_info = __gpa_to_mpa(vcpu->domain, gpa); - o_info = (u64)vcpu->domain->shared_info; - d->shared_info= (shared_info_t *)__va(shared_info); - - /* Copy existing shared info into new page */ - if (o_info) { - memcpy((void*)d->shared_info, (void*)o_info, PAGE_SIZE); - for_each_vcpu(d, v) { - v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; - } - /* If original page belongs to xen heap, then relinguish back - * to xen heap. Or else, leave to domain itself to decide. - */ - if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) - free_xenheap_page(o_info); - } else - memset(d->shared_info, 0, PAGE_SIZE); - return 0; -} - -void hyper_set_shared_page(void) -{ - VCPU *vcpu=current; - u64 gpa,ret; - vmx_vcpu_get_gr(vcpu,16,&gpa); - - ret=do_set_shared_page(vcpu, gpa); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); - - vmx_vcpu_increment_iip(vcpu); -} - -/* -void hyper_grant_table_op(void) -{ - VCPU *vcpu=current; - u64 r32,r33,r34,ret; - vmx_vcpu_get_gr(vcpu,16,&r32); - vmx_vcpu_get_gr(vcpu,17,&r33); - vmx_vcpu_get_gr(vcpu,18,&r34); - - ret=do_grant_table_op((unsigned int)r32, (void *)r33, (unsigned int)r34); - vmx_vcpu_set_gr(vcpu, 8, ret, 0); -} -*/ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_init.c --- a/xen/arch/ia64/vmx_init.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,375 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_init.c: initialization work for vt specific domain - * Copyright (c) 2005, Intel Corporation. - * Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) <anthony.xu@xxxxxxxxx> - * Fred Yang <fred.yang@xxxxxxxxx> - * - * 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. - * - */ - -/* - * 05/08/16 Kun tian (Kevin Tian) <kevin.tian@xxxxxxxxx>: - * Disable doubling mapping - * - * 05/03/23 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx>: - * Simplied design in first step: - * - One virtual environment - * - Domain is bound to one LP - * Later to support guest SMP: - * - Need interface to handle VP scheduled to different LP - */ -#include <xen/config.h> -#include <xen/types.h> -#include <xen/sched.h> -#include <asm/pal.h> -#include <asm/page.h> -#include <asm/processor.h> -#include <asm/vmx_vcpu.h> -#include <xen/lib.h> -#include <asm/vmmu.h> -#include <public/arch-ia64.h> -#include <public/io/ioreq.h> -#include <asm/vmx_phy_mode.h> -#include <asm/processor.h> -#include <asm/vmx.h> -#include <xen/mm.h> - -/* Global flag to identify whether Intel vmx feature is on */ -u32 vmx_enabled = 0; -static u32 vm_order; -static u64 buffer_size; -static u64 vp_env_info; -static u64 vm_buffer = 0; /* Buffer required to bring up VMX feature */ -u64 __vsa_base = 0; /* Run-time service base of VMX */ - -/* Check whether vt feature is enabled or not. */ -void -identify_vmx_feature(void) -{ - pal_status_t ret; - u64 avail = 1, status = 1, control = 1; - - vmx_enabled = 0; - /* Check VT-i feature */ - ret = ia64_pal_proc_get_features(&avail, &status, &control); - if (ret != PAL_STATUS_SUCCESS) { - printk("Get proc features failed.\n"); - goto no_vti; - } - - /* FIXME: do we need to check status field, to see whether - * PSR.vm is actually enabled? If yes, aonther call to - * ia64_pal_proc_set_features may be reuqired then. - */ - printk("avail:0x%lx, status:0x%lx,control:0x%lx, vm?0x%lx\n", - avail, status, control, avail & PAL_PROC_VM_BIT); - if (!(avail & PAL_PROC_VM_BIT)) { - printk("No VT feature supported.\n"); - goto no_vti; - } - - ret = ia64_pal_vp_env_info(&buffer_size, &vp_env_info); - if (ret != PAL_STATUS_SUCCESS) { - printk("Get vp environment info failed.\n"); - goto no_vti; - } - - /* Does xen has ability to decode itself? */ - if (!(vp_env_info & VP_OPCODE)) - printk("WARNING: no opcode provided from hardware(%lx)!!!\n", vp_env_info); - vm_order = get_order(buffer_size); - printk("vm buffer size: %d, order: %d\n", buffer_size, vm_order); - - vmx_enabled = 1; -no_vti: - return; -} - -/* - * Init virtual environment on current LP - * vsa_base is the indicator whether it's first LP to be initialized - * for current domain. - */ -void -vmx_init_env(void) -{ - u64 status, tmp_base; - - if (!vm_buffer) { - vm_buffer = alloc_xenheap_pages(vm_order); - ASSERT(vm_buffer); - printk("vm_buffer: 0x%lx\n", vm_buffer); - } - - status=ia64_pal_vp_init_env(__vsa_base ? VP_INIT_ENV : VP_INIT_ENV_INITALIZE, - __pa(vm_buffer), - vm_buffer, - &tmp_base); - - if (status != PAL_STATUS_SUCCESS) { - printk("ia64_pal_vp_init_env failed.\n"); - return -1; - } - - if (!__vsa_base) - __vsa_base = tmp_base; - else - ASSERT(tmp_base != __vsa_base); - -#ifdef XEN_DBL_MAPPING - /* Init stub for rr7 switch */ - vmx_init_double_mapping_stub(); -#endif -} - -void vmx_setup_platform(struct vcpu *v, struct vcpu_guest_context *c) -{ - struct domain *d = v->domain; - shared_iopage_t *sp; - - ASSERT(d != dom0); /* only for non-privileged vti domain */ - d->arch.vmx_platform.shared_page_va = __va(c->share_io_pg); - sp = get_sp(d); - memset((char *)sp,0,PAGE_SIZE); - /* FIXME: temp due to old CP */ - sp->sp_global.eport = 2; -#ifdef V_IOSAPIC_READY - sp->vcpu_number = 1; -#endif - /* TEMP */ - d->arch.vmx_platform.pib_base = 0xfee00000UL; - - /* One more step to enable interrupt assist */ - set_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags); - /* Only open one port for I/O and interrupt emulation */ - if (v == d->vcpu[0]) { - memset(&d->shared_info->evtchn_mask[0], 0xff, - sizeof(d->shared_info->evtchn_mask)); - clear_bit(iopacket_port(d), &d->shared_info->evtchn_mask[0]); - } - - /* FIXME: only support PMT table continuously by far */ - d->arch.pmt = __va(c->pt_base); - d->arch.max_pfn = c->pt_max_pfn; - - vmx_final_setup_domain(d); -} - -typedef union { - u64 value; - struct { - u64 number : 8; - u64 revision : 8; - u64 model : 8; - u64 family : 8; - u64 archrev : 8; - u64 rv : 24; - }; -} cpuid3_t; - -/* Allocate vpd from xenheap */ -static vpd_t *alloc_vpd(void) -{ - int i; - cpuid3_t cpuid3; - vpd_t *vpd; - - vpd = alloc_xenheap_pages(get_order(VPD_SIZE)); - if (!vpd) { - printk("VPD allocation failed.\n"); - return NULL; - } - - printk("vpd base: 0x%lx, vpd size:%d\n", vpd, sizeof(vpd_t)); - memset(vpd, 0, VPD_SIZE); - /* CPUID init */ - for (i = 0; i < 5; i++) - vpd->vcpuid[i] = ia64_get_cpuid(i); - - /* Limit the CPUID number to 5 */ - cpuid3.value = vpd->vcpuid[3]; - cpuid3.number = 4; /* 5 - 1 */ - vpd->vcpuid[3] = cpuid3.value; - - vpd->vdc.d_vmsw = 1; - return vpd; -} - - -#ifdef CONFIG_VTI -/* - * Create a VP on intialized VMX environment. - */ -static void -vmx_create_vp(struct vcpu *v) -{ - u64 ret; - vpd_t *vpd = v->arch.arch_vmx.vpd; - u64 ivt_base; - extern char vmx_ia64_ivt; - /* ia64_ivt is function pointer, so need this tranlation */ - ivt_base = (u64) &vmx_ia64_ivt; - printk("ivt_base: 0x%lx\n", ivt_base); - ret = ia64_pal_vp_create(vpd, ivt_base, 0); - if (ret != PAL_STATUS_SUCCESS) - panic("ia64_pal_vp_create failed. \n"); -} - -#ifdef XEN_DBL_MAPPING -void vmx_init_double_mapping_stub(void) -{ - u64 base, psr; - extern void vmx_switch_rr7(void); - - base = (u64) &vmx_switch_rr7; - base = *((u64*)base); - - psr = ia64_clear_ic(); - ia64_itr(0x1, IA64_TR_RR7_SWITCH_STUB, XEN_RR7_SWITCH_STUB, - pte_val(pfn_pte(__pa(base) >> PAGE_SHIFT, PAGE_KERNEL)), - RR7_SWITCH_SHIFT); - ia64_set_psr(psr); - ia64_srlz_i(); - printk("Add TR mapping for rr7 switch stub, with physical: 0x%lx\n", (u64)(__pa(base))); -} -#endif - -/* Other non-context related tasks can be done in context switch */ -void -vmx_save_state(struct vcpu *v) -{ - u64 status, psr; - u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; - - /* FIXME: about setting of pal_proc_vector... time consuming */ - status = ia64_pal_vp_save(v->arch.arch_vmx.vpd, 0); - if (status != PAL_STATUS_SUCCESS) - panic("Save vp status failed\n"); - -#ifdef XEN_DBL_MAPPING - /* FIXME: Do we really need purge double mapping for old vcpu? - * Since rid is completely different between prev and next, - * it's not overlap and thus no MCA possible... */ - dom_rr7 = vmx_vrrtomrr(v, VMX(v, vrr[7])); - vmx_purge_double_mapping(dom_rr7, KERNEL_START, - (u64)v->arch.vtlb->ts->vhpt->hash); -#endif - - /* Need to save KR when domain switch, though HV itself doesn;t - * use them. - */ - v->arch.arch_vmx.vkr[0] = ia64_get_kr(0); - v->arch.arch_vmx.vkr[1] = ia64_get_kr(1); - v->arch.arch_vmx.vkr[2] = ia64_get_kr(2); - v->arch.arch_vmx.vkr[3] = ia64_get_kr(3); - v->arch.arch_vmx.vkr[4] = ia64_get_kr(4); - v->arch.arch_vmx.vkr[5] = ia64_get_kr(5); - v->arch.arch_vmx.vkr[6] = ia64_get_kr(6); - v->arch.arch_vmx.vkr[7] = ia64_get_kr(7); -} - -/* Even guest is in physical mode, we still need such double mapping */ -void -vmx_load_state(struct vcpu *v) -{ - u64 status, psr; - u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; - u64 pte_xen, pte_vhpt; - int i; - - status = ia64_pal_vp_restore(v->arch.arch_vmx.vpd, 0); - if (status != PAL_STATUS_SUCCESS) - panic("Restore vp status failed\n"); - -#ifdef XEN_DBL_MAPPING - dom_rr7 = vmx_vrrtomrr(v, VMX(v, vrr[7])); - pte_xen = pte_val(pfn_pte((xen_pstart >> PAGE_SHIFT), PAGE_KERNEL)); - pte_vhpt = pte_val(pfn_pte((__pa(v->arch.vtlb->ts->vhpt->hash) >> PAGE_SHIFT), PAGE_KERNEL)); - vmx_insert_double_mapping(dom_rr7, KERNEL_START, - (u64)v->arch.vtlb->ts->vhpt->hash, - pte_xen, pte_vhpt); -#endif - - ia64_set_kr(0, v->arch.arch_vmx.vkr[0]); - ia64_set_kr(1, v->arch.arch_vmx.vkr[1]); - ia64_set_kr(2, v->arch.arch_vmx.vkr[2]); - ia64_set_kr(3, v->arch.arch_vmx.vkr[3]); - ia64_set_kr(4, v->arch.arch_vmx.vkr[4]); - ia64_set_kr(5, v->arch.arch_vmx.vkr[5]); - ia64_set_kr(6, v->arch.arch_vmx.vkr[6]); - ia64_set_kr(7, v->arch.arch_vmx.vkr[7]); - /* Guest vTLB is not required to be switched explicitly, since - * anchored in vcpu */ -} - -#ifdef XEN_DBL_MAPPING -/* Purge old double mapping and insert new one, due to rr7 change */ -void -vmx_change_double_mapping(struct vcpu *v, u64 oldrr7, u64 newrr7) -{ - u64 pte_xen, pte_vhpt, vhpt_base; - - vhpt_base = (u64)v->arch.vtlb->ts->vhpt->hash; - vmx_purge_double_mapping(oldrr7, KERNEL_START, - vhpt_base); - - pte_xen = pte_val(pfn_pte((xen_pstart >> PAGE_SHIFT), PAGE_KERNEL)); - pte_vhpt = pte_val(pfn_pte((__pa(vhpt_base) >> PAGE_SHIFT), PAGE_KERNEL)); - vmx_insert_double_mapping(newrr7, KERNEL_START, - vhpt_base, - pte_xen, pte_vhpt); -} -#endif // XEN_DBL_MAPPING -#endif // CONFIG_VTI - -/* - * Initialize VMX envirenment for guest. Only the 1st vp/vcpu - * is registered here. - */ -void -vmx_final_setup_domain(struct domain *d) -{ - struct vcpu *v = d->vcpu[0]; - vpd_t *vpd; - - /* Allocate resources for vcpu 0 */ - //memset(&v->arch.arch_vmx, 0, sizeof(struct arch_vmx_struct)); - - vpd = alloc_vpd(); - ASSERT(vpd); - - v->arch.arch_vmx.vpd = vpd; - vpd->virt_env_vaddr = vm_buffer; - -#ifdef CONFIG_VTI - /* v->arch.schedule_tail = arch_vmx_do_launch; */ - vmx_create_vp(v); - - /* Set this ed to be vmx */ - set_bit(ARCH_VMX_VMCS_LOADED, &v->arch.arch_vmx.flags); - - /* Physical mode emulation initialization, including - * emulation ID allcation and related memory request - */ - physical_mode_init(v); - - vlsapic_reset(v); - vtm_init(v); -#endif - - /* Other vmx specific initialization work */ -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_interrupt.c --- a/xen/arch/ia64/vmx_interrupt.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,388 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_interrupt.c: handle inject interruption. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> - * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - - -#include <xen/types.h> -#include <asm/vmx_vcpu.h> -#include <asm/vmx_mm_def.h> -#include <asm/vmx_pal_vsa.h> -/* SDM vol2 5.5 - IVA based interruption handling */ -#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 -void -collect_interruption(VCPU *vcpu) -{ - u64 ipsr; - u64 vdcr; - u64 vifs; - IA64_PSR vpsr; - REGS * regs = vcpu_regs(vcpu); - vpsr.val = vmx_vcpu_get_psr(vcpu); - - if(vpsr.ic){ - extern void vmx_dorfirfi(void); - if (regs->cr_iip == *(unsigned long *)vmx_dorfirfi) - panic("COLLECT interruption for vmx_dorfirfi\n"); - - /* Sync mpsr id/da/dd/ss/ed bits to vipsr - * since after guest do rfi, we still want these bits on in - * mpsr - */ - - ipsr = regs->cr_ipsr; - vpsr.val = vpsr.val | (ipsr & (IA64_PSR_ID | IA64_PSR_DA - | IA64_PSR_DD |IA64_PSR_SS |IA64_PSR_ED)); - vmx_vcpu_set_ipsr(vcpu, vpsr.val); - - /* Currently, for trap, we do not advance IIP to next - * instruction. That's because we assume caller already - * set up IIP correctly - */ - - vmx_vcpu_set_iip(vcpu , regs->cr_iip); - - /* set vifs.v to zero */ - vifs = VPD_CR(vcpu,ifs); - vifs &= ~IA64_IFS_V; - vmx_vcpu_set_ifs(vcpu, vifs); - - vmx_vcpu_set_iipa(vcpu, regs->cr_iipa); - } - - vdcr = VPD_CR(vcpu,dcr); - - /* Set guest psr - * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged - * be: set to the value of dcr.be - * pp: set to the value of dcr.pp - */ - vpsr.val &= INITIAL_PSR_VALUE_AT_INTERRUPTION; - vpsr.val |= ( vdcr & IA64_DCR_BE); - - /* VDCR pp bit position is different from VPSR pp bit */ - if ( vdcr & IA64_DCR_PP ) { - vpsr.val |= IA64_PSR_PP; - } else { - vpsr.val &= ~IA64_PSR_PP;; - } - - vmx_vcpu_set_psr(vcpu, vpsr.val); - -} -int -inject_guest_interruption(VCPU *vcpu, u64 vec) -{ - u64 viva; - REGS *regs; - regs=vcpu_regs(vcpu); - - collect_interruption(vcpu); - - vmx_vcpu_get_iva(vcpu,&viva); - regs->cr_iip = viva + vec; -} - - -/* - * Set vIFA & vITIR & vIHA, when vPSR.ic =1 - * Parameter: - * set_ifa: if true, set vIFA - * set_itir: if true, set vITIR - * set_iha: if true, set vIHA - */ -void -set_ifa_itir_iha (VCPU *vcpu, u64 vadr, - int set_ifa, int set_itir, int set_iha) -{ - IA64_PSR vpsr; - u64 value; - vpsr.val = vmx_vcpu_get_psr(vcpu); - /* Vol2, Table 8-1 */ - if ( vpsr.ic ) { - if ( set_ifa){ - vmx_vcpu_set_ifa(vcpu, vadr); - } - if ( set_itir) { - value = vmx_vcpu_get_itir_on_fault(vcpu, vadr); - vmx_vcpu_set_itir(vcpu, value); - } - - if ( set_iha) { - vmx_vcpu_thash(vcpu, vadr, &value); - vmx_vcpu_set_iha(vcpu, value); - } - } - - -} - -/* - * Data TLB Fault - * @ Data TLB vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -dtlb_fault (VCPU *vcpu, u64 vadr) -{ - /* If vPSR.ic, IFA, ITIR, IHA */ - set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); - inject_guest_interruption(vcpu,IA64_DATA_TLB_VECTOR); -} - -/* - * Instruction TLB Fault - * @ Instruction TLB vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -itlb_fault (VCPU *vcpu, u64 vadr) -{ - /* If vPSR.ic, IFA, ITIR, IHA */ - set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); - inject_guest_interruption(vcpu,IA64_INST_TLB_VECTOR); -} - - - -/* - * Data Nested TLB Fault - * @ Data Nested TLB Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -nested_dtlb (VCPU *vcpu) -{ - inject_guest_interruption(vcpu,IA64_DATA_NESTED_TLB_VECTOR); -} - -/* - * Alternate Data TLB Fault - * @ Alternate Data TLB vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -alt_dtlb (VCPU *vcpu, u64 vadr) -{ - set_ifa_itir_iha (vcpu, vadr, 1, 1, 0); - inject_guest_interruption(vcpu,IA64_ALT_DATA_TLB_VECTOR); -} - - -/* - * Data TLB Fault - * @ Data TLB vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -alt_itlb (VCPU *vcpu, u64 vadr) -{ - set_ifa_itir_iha (vcpu, vadr, 1, 1, 0); - inject_guest_interruption(vcpu,IA64_ALT_INST_TLB_VECTOR); -} - -/* Deal with: - * VHPT Translation Vector - */ -static void -_vhpt_fault(VCPU *vcpu, u64 vadr) -{ - /* If vPSR.ic, IFA, ITIR, IHA*/ - set_ifa_itir_iha (vcpu, vadr, 1, 1, 1); - inject_guest_interruption(vcpu,IA64_VHPT_TRANS_VECTOR); - - -} - -/* - * VHPT Instruction Fault - * @ VHPT Translation vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -ivhpt_fault (VCPU *vcpu, u64 vadr) -{ - _vhpt_fault(vcpu, vadr); -} - - -/* - * VHPT Data Fault - * @ VHPT Translation vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -dvhpt_fault (VCPU *vcpu, u64 vadr) -{ - _vhpt_fault(vcpu, vadr); -} - - - -/* - * Deal with: - * General Exception vector - */ -void -_general_exception (VCPU *vcpu) -{ - inject_guest_interruption(vcpu,IA64_GENEX_VECTOR); -} - - -/* - * Illegal Operation Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -illegal_op (VCPU *vcpu) -{ - _general_exception(vcpu); -} - -/* - * Illegal Dependency Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -illegal_dep (VCPU *vcpu) -{ - _general_exception(vcpu); -} - -/* - * Reserved Register/Field Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -rsv_reg_field (VCPU *vcpu) -{ - _general_exception(vcpu); -} -/* - * Privileged Operation Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ - -void -privilege_op (VCPU *vcpu) -{ - _general_exception(vcpu); -} - -/* - * Unimplement Data Address Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -unimpl_daddr (VCPU *vcpu) -{ - _general_exception(vcpu); -} - -/* - * Privileged Register Fault - * @ General Exception Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -privilege_reg (VCPU *vcpu) -{ - _general_exception(vcpu); -} - -/* Deal with - * Nat consumption vector - * Parameter: - * vaddr: Optional, if t == REGISTER - */ -static void -_nat_consumption_fault(VCPU *vcpu, u64 vadr, miss_type t) -{ - /* If vPSR.ic && t == DATA/INST, IFA */ - if ( t == DATA || t == INSTRUCTION ) { - /* IFA */ - set_ifa_itir_iha (vcpu, vadr, 1, 0, 0); - } - - inject_guest_interruption(vcpu,IA64_NAT_CONSUMPTION_VECTOR); -} - -/* - * IR Data Nat Page Consumption Fault - * @ Nat Consumption Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -static void -ir_nat_page_consumption (VCPU *vcpu, u64 vadr) -{ - _nat_consumption_fault(vcpu, vadr, DATA); -} - -/* - * Instruction Nat Page Consumption Fault - * @ Nat Consumption Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -inat_page_consumption (VCPU *vcpu, u64 vadr) -{ - _nat_consumption_fault(vcpu, vadr, INSTRUCTION); -} - -/* - * Register Nat Consumption Fault - * @ Nat Consumption Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -rnat_consumption (VCPU *vcpu) -{ - _nat_consumption_fault(vcpu, 0, REGISTER); -} - -/* - * Data Nat Page Consumption Fault - * @ Nat Consumption Vector - * Refer to SDM Vol2 Table 5-6 & 8-1 - */ -void -dnat_page_consumption (VCPU *vcpu, uint64_t vadr) -{ - _nat_consumption_fault(vcpu, vadr, DATA); -} - -/* Deal with - * Page not present vector - */ -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); -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_irq_ia64.c --- a/xen/arch/ia64/vmx_irq_ia64.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,127 +0,0 @@ -#include <linux/config.h> -#include <linux/module.h> - -#include <linux/jiffies.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/kernel_stat.h> -#include <linux/slab.h> -#include <linux/ptrace.h> -#include <linux/random.h> /* for rand_initialize_irq() */ -#include <linux/signal.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/threads.h> -#include <linux/bitops.h> - -#include <asm/delay.h> -#include <asm/intrinsics.h> -#include <asm/io.h> -#include <asm/hw_irq.h> -#include <asm/machvec.h> -#include <asm/pgtable.h> -#include <asm/system.h> - -#ifdef CONFIG_PERFMON -# include <asm/perfmon.h> -#endif - -#define IRQ_DEBUG 0 - -#ifdef CONFIG_VTI -#define vmx_irq_enter() \ - add_preempt_count(HARDIRQ_OFFSET); - -/* Now softirq will be checked when leaving hypervisor, or else - * scheduler irq will be executed too early. - */ -#define vmx_irq_exit(void) \ - sub_preempt_count(HARDIRQ_OFFSET); -/* - * That's where the IVT branches when we get an external - * interrupt. This branches to the correct hardware IRQ handler via - * function ptr. - */ -void -vmx_ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) -{ - unsigned long saved_tpr; - int wake_dom0 = 0; - - -#if IRQ_DEBUG - { - unsigned long bsp, sp; - - /* - * Note: if the interrupt happened while executing in - * the context switch routine (ia64_switch_to), we may - * get a spurious stack overflow here. This is - * because the register and the memory stack are not - * switched atomically. - */ - bsp = ia64_getreg(_IA64_REG_AR_BSP); - sp = ia64_getreg(_IA64_REG_AR_SP); - - if ((sp - bsp) < 1024) { - static unsigned char count; - static long last_time; - - if (jiffies - last_time > 5*HZ) - count = 0; - if (++count < 5) { - last_time = jiffies; - printk("ia64_handle_irq: DANGER: less than " - "1KB of free stack space!!\n" - "(bsp=0x%lx, sp=%lx)\n", bsp, sp); - } - } - } -#endif /* IRQ_DEBUG */ - - /* - * Always set TPR to limit maximum interrupt nesting depth to - * 16 (without this, it would be ~240, which could easily lead - * to kernel stack overflows). - */ - vmx_irq_enter(); - saved_tpr = ia64_getreg(_IA64_REG_CR_TPR); - ia64_srlz_d(); - while (vector != IA64_SPURIOUS_INT_VECTOR) { - if (!IS_RESCHEDULE(vector)) { - ia64_setreg(_IA64_REG_CR_TPR, vector); - ia64_srlz_d(); - - if (vector != IA64_TIMER_VECTOR) { - /* FIXME: Leave IRQ re-route later */ - vmx_vcpu_pend_interrupt(dom0->vcpu[0],vector); - wake_dom0 = 1; - } - else { // FIXME: Handle Timer only now - __do_IRQ(local_vector_to_irq(vector), regs); - } - - /* - * Disable interrupts and send EOI: - */ - local_irq_disable(); - ia64_setreg(_IA64_REG_CR_TPR, saved_tpr); - } - else { - printf("Oops: RESCHEDULE IPI absorbed by HV\n"); - } - ia64_eoi(); - vector = ia64_get_ivr(); - } - /* - * This must be done *after* the ia64_eoi(). For example, the keyboard softirq - * handler needs to be able to wait for further keyboard interrupts, which can't - * come through until ia64_eoi() has been done. - */ - vmx_irq_exit(); - if ( wake_dom0 && current != dom0 ) - vcpu_wake(dom0->vcpu[0]); -} -#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_ivt.S --- a/xen/arch/ia64/vmx_ivt.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1085 +0,0 @@ -/* - * arch/ia64/kernel/vmx_ivt.S - * - * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co - * Stephane Eranian <eranian@xxxxxxxxxx> - * David Mosberger <davidm@xxxxxxxxxx> - * Copyright (C) 2000, 2002-2003 Intel Co - * Asit Mallick <asit.k.mallick@xxxxxxxxx> - * Suresh Siddha <suresh.b.siddha@xxxxxxxxx> - * Kenneth Chen <kenneth.w.chen@xxxxxxxxx> - * Fenghua Yu <fenghua.yu@xxxxxxxxx> - * - * - * 00/08/23 Asit Mallick <asit.k.mallick@xxxxxxxxx> TLB handling for SMP - * 00/12/20 David Mosberger-Tang <davidm@xxxxxxxxxx> DTLB/ITLB handler now uses virtual PT. - * - * 05/3/20 Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) - * Supporting Intel virtualization architecture - * - */ - -/* - * This file defines the interruption vector table used by the CPU. - * It does not include one entry per possible cause of interruption. - * - * The first 20 entries of the table contain 64 bundles each while the - * remaining 48 entries contain only 16 bundles each. - * - * The 64 bundles are used to allow inlining the whole handler for critical - * interruptions like TLB misses. - * - * For each entry, the comment is as follows: - * - * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) - * entry offset ----/ / / / / - * entry number ---------/ / / / - * size of the entry -------------/ / / - * vector name -------------------------------------/ / - * interruptions triggering this vector ----------------------/ - * - * The table is 32KB in size and must be aligned on 32KB boundary. - * (The CPU ignores the 15 lower bits of the address) - * - * Table is based upon EAS2.6 (Oct 1999) - */ - -#include <linux/config.h> - -#include <asm/asmmacro.h> -#include <asm/break.h> -#include <asm/ia32.h> -#include <asm/kregs.h> -#include <asm/offsets.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/system.h> -#include <asm/thread_info.h> -#include <asm/unistd.h> -#include <asm/vhpt.h> - - -#if 0 - /* - * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't - * needed for something else before enabling this... - */ -# define VMX_DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 -#else -# define VMX_DBG_FAULT(i) -#endif - -#include "vmx_minstate.h" - - - -#define VMX_FAULT(n) \ -vmx_fault_##n:; \ - br.sptk vmx_fault_##n; \ - ;; \ - - -#define VMX_REFLECT(n) \ - mov r31=pr; \ - mov r19=n; /* prepare to save predicates */ \ - mov r29=cr.ipsr; \ - ;; \ - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \ -(p7) br.sptk.many vmx_dispatch_reflection; \ - VMX_FAULT(n); \ - - -GLOBAL_ENTRY(vmx_panic) - br.sptk.many vmx_panic - ;; -END(vmx_panic) - - - - - - .section .text.ivt,"ax" - - .align 32768 // align on 32KB boundary - .global vmx_ia64_ivt -vmx_ia64_ivt: -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) -ENTRY(vmx_vhpt_miss) - VMX_FAULT(0) -END(vmx_vhpt_miss) - - .org vmx_ia64_ivt+0x400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0400 Entry 1 (size 64 bundles) ITLB (21) -ENTRY(vmx_itlb_miss) - mov r31 = pr - mov r29=cr.ipsr; - ;; - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; -(p6) br.sptk vmx_fault_1 - mov r16 = cr.ifa - ;; - thash r17 = r16 - ttag r20 = r16 - ;; -vmx_itlb_loop: - cmp.eq p6,p0 = r0, r17 -(p6) br vmx_itlb_out - ;; - adds r22 = VLE_TITAG_OFFSET, r17 - adds r23 = VLE_CCHAIN_OFFSET, r17 - ;; - ld8 r24 = [r22] - ld8 r25 = [r23] - ;; - lfetch [r25] - cmp.eq p6,p7 = r20, r24 - ;; -(p7) mov r17 = r25; -(p7) br.sptk vmx_itlb_loop - ;; - adds r23 = VLE_PGFLAGS_OFFSET, r17 - adds r24 = VLE_ITIR_OFFSET, r17 - ;; - ld8 r26 = [r23] - ld8 r25 = [r24] - ;; - mov cr.itir = r25 - ;; - itc.i r26 - ;; - srlz.i - ;; - mov r23=r31 - mov r22=b0 - adds r16=IA64_VPD_BASE_OFFSET,r21 - ;; - ld8 r18=[r16] - ;; - adds r19=VPD(VPSR),r18 - movl r20=__vsa_base - ;; - ld8 r19=[r19] - ld8 r20=[r20] - ;; - br.sptk ia64_vmm_entry - ;; -vmx_itlb_out: - mov r19 = 1 - br.sptk vmx_dispatch_tlb_miss - VMX_FAULT(1); -END(vmx_itlb_miss) - - .org vmx_ia64_ivt+0x0800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) -ENTRY(vmx_dtlb_miss) - mov r31 = pr - mov r29=cr.ipsr; - ;; - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; -(p6)br.sptk vmx_fault_2 - mov r16 = cr.ifa - ;; - thash r17 = r16 - ttag r20 = r16 - ;; -vmx_dtlb_loop: - cmp.eq p6,p0 = r0, r17 -(p6)br vmx_dtlb_out - ;; - adds r22 = VLE_TITAG_OFFSET, r17 - adds r23 = VLE_CCHAIN_OFFSET, r17 - ;; - ld8 r24 = [r22] - ld8 r25 = [r23] - ;; - lfetch [r25] - cmp.eq p6,p7 = r20, r24 - ;; -(p7)mov r17 = r25; -(p7)br.sptk vmx_dtlb_loop - ;; - adds r23 = VLE_PGFLAGS_OFFSET, r17 - adds r24 = VLE_ITIR_OFFSET, r17 - ;; - ld8 r26 = [r23] - ld8 r25 = [r24] - ;; - mov cr.itir = r25 - ;; - itc.d r26 - ;; - srlz.d; - ;; - mov r23=r31 - mov r22=b0 - adds r16=IA64_VPD_BASE_OFFSET,r21 - ;; - ld8 r18=[r16] - ;; - adds r19=VPD(VPSR),r18 - movl r20=__vsa_base - ;; - ld8 r19=[r19] - ld8 r20=[r20] - ;; - br.sptk ia64_vmm_entry - ;; -vmx_dtlb_out: - mov r19 = 2 - br.sptk vmx_dispatch_tlb_miss - VMX_FAULT(2); -END(vmx_dtlb_miss) - - .org vmx_ia64_ivt+0x0c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) -ENTRY(vmx_alt_itlb_miss) - mov r31 = pr - mov r29=cr.ipsr; - ;; - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; -(p7)br.sptk vmx_fault_3 - mov r16=cr.ifa // get address that caused the TLB miss - movl r17=PAGE_KERNEL - mov r24=cr.ipsr - movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) - ;; - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits - shr.u r18=r16,55 // move address bit 59 to bit 4 - ;; - and r18=0x10,r18 // bit 4=address-bit(61) - or r19=r17,r19 // insert PTE control bits into r19 - ;; - or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 - ;; - itc.i r19 // insert the TLB entry - mov pr=r31,-1 - rfi - VMX_FAULT(3); -END(vmx_alt_itlb_miss) - - - .org vmx_ia64_ivt+0x1000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) -ENTRY(vmx_alt_dtlb_miss) - mov r31=pr - mov r29=cr.ipsr; - ;; - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; -(p7)br.sptk vmx_fault_4 - mov r16=cr.ifa // get address that caused the TLB miss - movl r17=PAGE_KERNEL - mov r20=cr.isr - movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) - mov r24=cr.ipsr - ;; - and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field - tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? - shr.u r18=r16,55 // move address bit 59 to bit 4 - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits - tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? - ;; - and r18=0x10,r18 // bit 4=address-bit(61) -(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field - dep r24=-1,r24,IA64_PSR_ED_BIT,1 - or r19=r19,r17 // insert PTE control bits into r19 - ;; - or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 -(p6) mov cr.ipsr=r24 - ;; -(p7) itc.d r19 // insert the TLB entry - mov pr=r31,-1 - rfi - VMX_FAULT(4); -END(vmx_alt_dtlb_miss) - - .org vmx_ia64_ivt+0x1400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) -ENTRY(vmx_nested_dtlb_miss) - VMX_FAULT(5) -END(vmx_nested_dtlb_miss) - - .org vmx_ia64_ivt+0x1800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) -ENTRY(vmx_ikey_miss) - VMX_REFLECT(6) -END(vmx_ikey_miss) - - .org vmx_ia64_ivt+0x1c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) -ENTRY(vmx_dkey_miss) - VMX_REFLECT(7) -END(vmx_dkey_miss) - - .org vmx_ia64_ivt+0x2000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) -ENTRY(vmx_dirty_bit) - VMX_REFLECT(8) -END(vmx_idirty_bit) - - .org vmx_ia64_ivt+0x2400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) -ENTRY(vmx_iaccess_bit) - VMX_REFLECT(9) -END(vmx_iaccess_bit) - - .org vmx_ia64_ivt+0x2800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) -ENTRY(vmx_daccess_bit) - VMX_REFLECT(10) -END(vmx_daccess_bit) - - .org vmx_ia64_ivt+0x2c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) -ENTRY(vmx_break_fault) - mov r31=pr - mov r19=11 - mov r30=cr.iim - movl r29=0x1100 - ;; - cmp.eq p6,p7=r30,r0 - (p6) br.sptk vmx_fault_11 - ;; - cmp.eq p6,p7=r29,r30 - (p6) br.dptk.few vmx_hypercall_dispatch - (p7) br.sptk.many vmx_dispatch_break_fault - ;; - VMX_FAULT(11); -END(vmx_break_fault) - - .org vmx_ia64_ivt+0x3000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) -ENTRY(vmx_interrupt) - mov r31=pr // prepare to save predicates - mov r19=12 - mov r29=cr.ipsr - ;; - tbit.z p6,p7=r29,IA64_PSR_VM_BIT - tbit.z p0,p15=r29,IA64_PSR_I_BIT - ;; -(p7) br.sptk vmx_dispatch_interrupt - ;; - mov r27=ar.rsc /* M */ - mov r20=r1 /* A */ - mov r25=ar.unat /* M */ - mov r26=ar.pfs /* I */ - mov r28=cr.iip /* M */ - cover /* B (or nothing) */ - ;; - mov r1=sp - ;; - invala /* M */ - mov r30=cr.ifs - ;; - addl r1=-IA64_PT_REGS_SIZE,r1 - ;; - adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line size */ - adds r16=PT(CR_IPSR),r1 - ;; - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES - st8 [r16]=r29 /* save cr.ipsr */ - ;; - lfetch.fault.excl.nt1 [r17] - mov r29=b0 - ;; - adds r16=PT(R8),r1 /* initialize first base pointer */ - adds r17=PT(R9),r1 /* initialize second base pointer */ - mov r18=r0 /* make sure r18 isn't NaT */ - ;; -.mem.offset 0,0; st8.spill [r16]=r8,16 -.mem.offset 8,0; st8.spill [r17]=r9,16 - ;; -.mem.offset 0,0; st8.spill [r16]=r10,24 -.mem.offset 8,0; st8.spill [r17]=r11,24 - ;; - st8 [r16]=r28,16 /* save cr.iip */ - st8 [r17]=r30,16 /* save cr.ifs */ - mov r8=ar.fpsr /* M */ - mov r9=ar.csd - mov r10=ar.ssd - movl r11=FPSR_DEFAULT /* L-unit */ - ;; - st8 [r16]=r25,16 /* save ar.unat */ - st8 [r17]=r26,16 /* save ar.pfs */ - shl r18=r18,16 /* compute ar.rsc to be used for "loadrs" */ - ;; - st8 [r16]=r27,16 /* save ar.rsc */ - adds r17=16,r17 /* skip over ar_rnat field */ - ;; /* avoid RAW on r16 & r17 */ - st8 [r17]=r31,16 /* save predicates */ - adds r16=16,r16 /* skip over ar_bspstore field */ - ;; - st8 [r16]=r29,16 /* save b0 */ - st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */ - ;; -.mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */ -.mem.offset 8,0; st8.spill [r17]=r12,16 - adds r12=-16,r1 /* switch to kernel memory stack (with 16 bytes of scratch) */ - ;; -.mem.offset 0,0; st8.spill [r16]=r13,16 -.mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */ - mov r13=r21 /* establish `current' */ - ;; -.mem.offset 0,0; st8.spill [r16]=r15,16 -.mem.offset 8,0; st8.spill [r17]=r14,16 - dep r14=-1,r0,60,4 - ;; -.mem.offset 0,0; st8.spill [r16]=r2,16 -.mem.offset 8,0; st8.spill [r17]=r3,16 - adds r2=IA64_PT_REGS_R16_OFFSET,r1 - ;; - mov r8=ar.ccv - movl r1=__gp /* establish kernel global pointer */ - ;; \ - bsw.1 - ;; - alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group - mov out0=cr.ivr // pass cr.ivr as first arg - add out1=16,sp // pass pointer to pt_regs as second arg - - ssm psr.ic - ;; - srlz.i - ;; - (p15) ssm psr.i - adds r3=8,r2 // set up second base pointer for SAVE_REST - srlz.i // ensure everybody knows psr.ic is back on - ;; -.mem.offset 0,0; st8.spill [r2]=r16,16 -.mem.offset 8,0; st8.spill [r3]=r17,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r18,16 -.mem.offset 8,0; st8.spill [r3]=r19,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r20,16 -.mem.offset 8,0; st8.spill [r3]=r21,16 - mov r18=b6 - ;; -.mem.offset 0,0; st8.spill [r2]=r22,16 -.mem.offset 8,0; st8.spill [r3]=r23,16 - mov r19=b7 - ;; -.mem.offset 0,0; st8.spill [r2]=r24,16 -.mem.offset 8,0; st8.spill [r3]=r25,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r26,16 -.mem.offset 8,0; st8.spill [r3]=r27,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r28,16 -.mem.offset 8,0; st8.spill [r3]=r29,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r30,16 -.mem.offset 8,0; st8.spill [r3]=r31,32 - ;; - mov ar.fpsr=r11 /* M-unit */ - st8 [r2]=r8,8 /* ar.ccv */ - adds r24=PT(B6)-PT(F7),r3 - ;; - stf.spill [r2]=f6,32 - stf.spill [r3]=f7,32 - ;; - stf.spill [r2]=f8,32 - stf.spill [r3]=f9,32 - ;; - stf.spill [r2]=f10 - stf.spill [r3]=f11 - adds r25=PT(B7)-PT(F11),r3 - ;; - st8 [r24]=r18,16 /* b6 */ - st8 [r25]=r19,16 /* b7 */ - ;; - st8 [r24]=r9 /* ar.csd */ - st8 [r25]=r10 /* ar.ssd */ - ;; - srlz.d // make sure we see the effect of cr.ivr - movl r14=ia64_leave_nested - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_ia64_handle_irq - ;; -END(vmx_interrupt) - - .org vmx_ia64_ivt+0x3400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3400 Entry 13 (size 64 bundles) Reserved -ENTRY(vmx_virtual_exirq) - VMX_DBG_FAULT(13) - mov r31=pr - mov r19=13 - br.sptk vmx_dispatch_vexirq -END(vmx_virtual_exirq) - - .org vmx_ia64_ivt+0x3800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3800 Entry 14 (size 64 bundles) Reserved - VMX_DBG_FAULT(14) - VMX_FAULT(14) - - - .org vmx_ia64_ivt+0x3c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x3c00 Entry 15 (size 64 bundles) Reserved - VMX_DBG_FAULT(15) - VMX_FAULT(15) - - - .org vmx_ia64_ivt+0x4000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4000 Entry 16 (size 64 bundles) Reserved - VMX_DBG_FAULT(16) - VMX_FAULT(16) - - .org vmx_ia64_ivt+0x4400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4400 Entry 17 (size 64 bundles) Reserved - VMX_DBG_FAULT(17) - VMX_FAULT(17) - - .org vmx_ia64_ivt+0x4800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4800 Entry 18 (size 64 bundles) Reserved - VMX_DBG_FAULT(18) - VMX_FAULT(18) - - .org vmx_ia64_ivt+0x4c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x4c00 Entry 19 (size 64 bundles) Reserved - VMX_DBG_FAULT(19) - VMX_FAULT(19) - - .org vmx_ia64_ivt+0x5000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5000 Entry 20 (size 16 bundles) Page Not Present -ENTRY(vmx_page_not_present) - VMX_REFLECT(20) -END(vmx_page_not_present) - - .org vmx_ia64_ivt+0x5100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5100 Entry 21 (size 16 bundles) Key Permission vector -ENTRY(vmx_key_permission) - VMX_REFLECT(21) -END(vmx_key_permission) - - .org vmx_ia64_ivt+0x5200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) -ENTRY(vmx_iaccess_rights) - VMX_REFLECT(22) -END(vmx_iaccess_rights) - - .org vmx_ia64_ivt+0x5300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) -ENTRY(vmx_daccess_rights) - VMX_REFLECT(23) -END(vmx_daccess_rights) - - .org vmx_ia64_ivt+0x5400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) -ENTRY(vmx_general_exception) - VMX_FAULT(24) -// VMX_REFLECT(24) -END(vmx_general_exception) - - .org vmx_ia64_ivt+0x5500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) -ENTRY(vmx_disabled_fp_reg) - VMX_REFLECT(25) -END(vmx_disabled_fp_reg) - - .org vmx_ia64_ivt+0x5600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) -ENTRY(vmx_nat_consumption) - VMX_REFLECT(26) -END(vmx_nat_consumption) - - .org vmx_ia64_ivt+0x5700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5700 Entry 27 (size 16 bundles) Speculation (40) -ENTRY(vmx_speculation_vector) - VMX_REFLECT(27) -END(vmx_speculation_vector) - - .org vmx_ia64_ivt+0x5800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5800 Entry 28 (size 16 bundles) Reserved - VMX_DBG_FAULT(28) - VMX_FAULT(28) - - .org vmx_ia64_ivt+0x5900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) -ENTRY(vmx_debug_vector) - VMX_DBG_FAULT(29) - VMX_FAULT(29) -END(vmx_debug_vector) - - .org vmx_ia64_ivt+0x5a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) -ENTRY(vmx_unaligned_access) - VMX_REFLECT(30) -END(vmx_unaligned_access) - - .org vmx_ia64_ivt+0x5b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) -ENTRY(vmx_unsupported_data_reference) - VMX_REFLECT(31) -END(vmx_unsupported_data_reference) - - .org vmx_ia64_ivt+0x5c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) -ENTRY(vmx_floating_point_fault) - VMX_REFLECT(32) -END(vmx_floating_point_fault) - - .org vmx_ia64_ivt+0x5d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) -ENTRY(vmx_floating_point_trap) - VMX_REFLECT(33) -END(vmx_floating_point_trap) - - .org vmx_ia64_ivt+0x5e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) -ENTRY(vmx_lower_privilege_trap) - VMX_REFLECT(34) -END(vmx_lower_privilege_trap) - - .org vmx_ia64_ivt+0x5f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) -ENTRY(vmx_taken_branch_trap) - VMX_REFLECT(35) -END(vmx_taken_branch_trap) - - .org vmx_ia64_ivt+0x6000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) -ENTRY(vmx_single_step_trap) - VMX_REFLECT(36) -END(vmx_single_step_trap) - - .org vmx_ia64_ivt+0x6100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6100 Entry 37 (size 16 bundles) Virtualization Fault -ENTRY(vmx_virtualization_fault) - VMX_DBG_FAULT(37) - mov r31=pr - mov r19=37 - br.sptk vmx_dispatch_virtualization_fault -END(vmx_virtualization_fault) - - .org vmx_ia64_ivt+0x6200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6200 Entry 38 (size 16 bundles) Reserved - VMX_DBG_FAULT(38) - VMX_FAULT(38) - - .org vmx_ia64_ivt+0x6300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6300 Entry 39 (size 16 bundles) Reserved - VMX_DBG_FAULT(39) - VMX_FAULT(39) - - .org vmx_ia64_ivt+0x6400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6400 Entry 40 (size 16 bundles) Reserved - VMX_DBG_FAULT(40) - VMX_FAULT(40) - - .org vmx_ia64_ivt+0x6500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6500 Entry 41 (size 16 bundles) Reserved - VMX_DBG_FAULT(41) - VMX_FAULT(41) - - .org vmx_ia64_ivt+0x6600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6600 Entry 42 (size 16 bundles) Reserved - VMX_DBG_FAULT(42) - VMX_FAULT(42) - - .org vmx_ia64_ivt+0x6700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6700 Entry 43 (size 16 bundles) Reserved - VMX_DBG_FAULT(43) - VMX_FAULT(43) - - .org vmx_ia64_ivt+0x6800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6800 Entry 44 (size 16 bundles) Reserved - VMX_DBG_FAULT(44) - VMX_FAULT(44) - - .org vmx_ia64_ivt+0x6900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) -ENTRY(vmx_ia32_exception) - VMX_DBG_FAULT(45) - VMX_FAULT(45) -END(vmx_ia32_exception) - - .org vmx_ia64_ivt+0x6a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) -ENTRY(vmx_ia32_intercept) - VMX_DBG_FAULT(46) - VMX_FAULT(46) -END(vmx_ia32_intercept) - - .org vmx_ia64_ivt+0x6b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) -ENTRY(vmx_ia32_interrupt) - VMX_DBG_FAULT(47) - VMX_FAULT(47) -END(vmx_ia32_interrupt) - - .org vmx_ia64_ivt+0x6c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6c00 Entry 48 (size 16 bundles) Reserved - VMX_DBG_FAULT(48) - VMX_FAULT(48) - - .org vmx_ia64_ivt+0x6d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6d00 Entry 49 (size 16 bundles) Reserved - VMX_DBG_FAULT(49) - VMX_FAULT(49) - - .org vmx_ia64_ivt+0x6e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6e00 Entry 50 (size 16 bundles) Reserved - VMX_DBG_FAULT(50) - VMX_FAULT(50) - - .org vmx_ia64_ivt+0x6f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x6f00 Entry 51 (size 16 bundles) Reserved - VMX_DBG_FAULT(51) - VMX_FAULT(51) - - .org vmx_ia64_ivt+0x7000 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7000 Entry 52 (size 16 bundles) Reserved - VMX_DBG_FAULT(52) - VMX_FAULT(52) - - .org vmx_ia64_ivt+0x7100 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7100 Entry 53 (size 16 bundles) Reserved - VMX_DBG_FAULT(53) - VMX_FAULT(53) - - .org vmx_ia64_ivt+0x7200 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7200 Entry 54 (size 16 bundles) Reserved - VMX_DBG_FAULT(54) - VMX_FAULT(54) - - .org vmx_ia64_ivt+0x7300 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7300 Entry 55 (size 16 bundles) Reserved - VMX_DBG_FAULT(55) - VMX_FAULT(55) - - .org vmx_ia64_ivt+0x7400 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7400 Entry 56 (size 16 bundles) Reserved - VMX_DBG_FAULT(56) - VMX_FAULT(56) - - .org vmx_ia64_ivt+0x7500 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7500 Entry 57 (size 16 bundles) Reserved - VMX_DBG_FAULT(57) - VMX_FAULT(57) - - .org vmx_ia64_ivt+0x7600 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7600 Entry 58 (size 16 bundles) Reserved - VMX_DBG_FAULT(58) - VMX_FAULT(58) - - .org vmx_ia64_ivt+0x7700 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7700 Entry 59 (size 16 bundles) Reserved - VMX_DBG_FAULT(59) - VMX_FAULT(59) - - .org vmx_ia64_ivt+0x7800 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7800 Entry 60 (size 16 bundles) Reserved - VMX_DBG_FAULT(60) - VMX_FAULT(60) - - .org vmx_ia64_ivt+0x7900 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7900 Entry 61 (size 16 bundles) Reserved - VMX_DBG_FAULT(61) - VMX_FAULT(61) - - .org vmx_ia64_ivt+0x7a00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7a00 Entry 62 (size 16 bundles) Reserved - VMX_DBG_FAULT(62) - VMX_FAULT(62) - - .org vmx_ia64_ivt+0x7b00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7b00 Entry 63 (size 16 bundles) Reserved - VMX_DBG_FAULT(63) - VMX_FAULT(63) - - .org vmx_ia64_ivt+0x7c00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7c00 Entry 64 (size 16 bundles) Reserved - VMX_DBG_FAULT(64) - VMX_FAULT(64) - - .org vmx_ia64_ivt+0x7d00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7d00 Entry 65 (size 16 bundles) Reserved - VMX_DBG_FAULT(65) - VMX_FAULT(65) - - .org vmx_ia64_ivt+0x7e00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7e00 Entry 66 (size 16 bundles) Reserved - VMX_DBG_FAULT(66) - VMX_FAULT(66) - - .org vmx_ia64_ivt+0x7f00 -///////////////////////////////////////////////////////////////////////////////////////// -// 0x7f00 Entry 67 (size 16 bundles) Reserved - VMX_DBG_FAULT(67) - VMX_FAULT(67) - - .org vmx_ia64_ivt+0x8000 - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... - - -ENTRY(vmx_dispatch_reflection) - /* - * Input: - * psr.ic: off - * r19: intr type (offset into ivt, see ia64_int.h) - * r31: contains saved predicates (pr) - */ - VMX_SAVE_MIN_WITH_COVER_R19 - alloc r14=ar.pfs,0,0,4,0 - mov out0=cr.ifa - mov out1=cr.isr - mov out2=cr.iim - mov out3=r15 - - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15) ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_reflect_interruption -END(vmx_dispatch_reflection) - -ENTRY(vmx_dispatch_virtualization_fault) - VMX_SAVE_MIN_WITH_COVER_R19 - ;; - alloc r14=ar.pfs,0,0,3,0 // now it's safe (must be first in insn group!) - mov out0=r13 //vcpu - mov out1=r4 //cause - mov out2=r5 //opcode - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15) ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_emulate -END(vmx_dispatch_virtualization_fault) - - -ENTRY(vmx_dispatch_vexirq) - VMX_SAVE_MIN_WITH_COVER_R19 - alloc r14=ar.pfs,0,0,1,0 - mov out0=r13 - - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15) ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_vexirq -END(vmx_dispatch_vexirq) - -ENTRY(vmx_dispatch_tlb_miss) - VMX_SAVE_MIN_WITH_COVER_R19 - alloc r14=ar.pfs,0,0,3,0 - mov out0=r13 - mov out1=r15 - mov out2=cr.ifa - - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15) ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_hpw_miss -END(vmx_dispatch_tlb_miss) - - -ENTRY(vmx_dispatch_break_fault) - VMX_SAVE_MIN_WITH_COVER_R19 - ;; - ;; - alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) - mov out0=cr.ifa - adds out1=16,sp - mov out2=cr.isr // FIXME: pity to make this slow access twice - mov out3=cr.iim // FIXME: pity to make this slow access twice - - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15)ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_ia64_handle_break - ;; -END(vmx_dispatch_break_fault) - - -ENTRY(vmx_hypercall_dispatch) - VMX_SAVE_MIN_WITH_COVER - ssm psr.ic - ;; - srlz.i // guarantee that interruption collection is on - ;; - (p15) ssm psr.i // restore psr.i - adds r3=16,r2 // set up second base pointer - ;; - VMX_SAVE_REST - ;; - movl r14=ia64_leave_hypervisor - movl r2=hyper_call_table - ;; - mov rp=r14 - shladd r2=r15,3,r2 - ;; - ld8 r2=[r2] - ;; - mov b6=r2 - ;; - br.call.sptk.many b6=b6 - ;; -END(vmx_hypercall_dispatch) - - - -ENTRY(vmx_dispatch_interrupt) - VMX_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3 - ;; - alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group - mov out0=cr.ivr // pass cr.ivr as first arg - add out1=16,sp // pass pointer to pt_regs as second arg - - ssm psr.ic - ;; - srlz.i - ;; - (p15) ssm psr.i - adds r3=16,r2 // set up second base pointer for SAVE_REST - ;; - VMX_SAVE_REST - movl r14=ia64_leave_hypervisor - ;; - mov rp=r14 - br.call.sptk.many b6=vmx_ia64_handle_irq -END(vmx_dispatch_interrupt) - - - - .rodata - .align 8 - .globl hyper_call_table -hyper_call_table: - data8 hyper_not_support //hyper_set_trap_table /* 0 */ - data8 hyper_mmu_update - data8 hyper_not_support //hyper_set_gdt - data8 hyper_not_support //hyper_stack_switch - data8 hyper_not_support //hyper_set_callbacks - data8 hyper_not_support //hyper_fpu_taskswitch /* 5 */ - data8 hyper_sched_op - data8 hyper_dom0_op - data8 hyper_not_support //hyper_set_debugreg - data8 hyper_not_support //hyper_get_debugreg - data8 hyper_not_support //hyper_update_descriptor /* 10 */ - data8 hyper_not_support //hyper_set_fast_trap - data8 hyper_dom_mem_op - data8 hyper_not_support //hyper_multicall - data8 hyper_not_support //hyper_update_va_mapping - data8 hyper_not_support //hyper_set_timer_op /* 15 */ - data8 hyper_event_channel_op - data8 hyper_xen_version - data8 hyper_not_support //hyper_console_io - data8 hyper_not_support //hyper_physdev_op - data8 hyper_not_support //hyper_grant_table_op /* 20 */ - data8 hyper_not_support //hyper_vm_assist - data8 hyper_not_support //hyper_update_va_mapping_otherdomain - data8 hyper_not_support //hyper_switch_vm86 - data8 hyper_not_support //hyper_boot_vcpu - data8 hyper_not_support //hyper_ni_hypercall /* 25 */ - data8 hyper_not_support //hyper_mmuext_op - data8 hyper_lock_page - data8 hyper_set_shared_page diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_minstate.h --- a/xen/arch/ia64/vmx_minstate.h Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,333 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_minstate.h: - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <linux/config.h> - -#include <asm/asmmacro.h> -#include <asm/fpu.h> -#include <asm/mmu_context.h> -#include <asm/offsets.h> -#include <asm/pal.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/system.h> -#include <asm/vmx_pal_vsa.h> -#include <asm/vmx_vpd.h> -#include <asm/cache.h> -#include "entry.h" - -#define VMX_MINSTATE_START_SAVE_MIN \ - mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ - ;; \ - mov.m r28=ar.rnat; \ - addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ - ;; \ - lfetch.fault.excl.nt1 [r22]; \ - addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ - mov r23=ar.bspstore; /* save ar.bspstore */ \ - ;; \ - mov ar.bspstore=r22; /* switch to kernel RBS */ \ - ;; \ - mov r18=ar.bsp; \ - mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ - - - -#define VMX_MINSTATE_END_SAVE_MIN \ - bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ - ;; - - -#define PAL_VSA_SYNC_READ_CLEANUP_PSR_PL \ - /* begin to call pal vps sync_read and cleanup psr.pl */ \ - add r25=IA64_VPD_BASE_OFFSET, r21; \ - movl r20=__vsa_base; \ - ;; \ - ld8 r25=[r25]; /* read vpd base */ \ - ld8 r20=[r20]; /* read entry point */ \ - ;; \ - mov r6=r25; \ - add r20=PAL_VPS_SYNC_READ,r20; \ - ;; \ -{ .mii; \ - add r22=VPD(VPSR),r25; \ - mov r24=ip; \ - mov b0=r20; \ - ;; \ -}; \ -{ .mmb; \ - add r24 = 0x20, r24; \ - mov r16 = cr.ipsr; /* Temp workaround since psr.ic is off */ \ - br.cond.sptk b0; /* call the service */ \ - ;; \ -}; \ - ld8 r7=[r22]; \ - /* deposite ipsr bit cpl into vpd.vpsr, since epc will change */ \ - extr.u r30=r16, IA64_PSR_CPL0_BIT, 2; \ - ;; \ - dep r7=r30, r7, IA64_PSR_CPL0_BIT, 2; \ - ;; \ - extr.u r30=r16, IA64_PSR_BE_BIT, 5; \ - ;; \ - dep r7=r30, r7, IA64_PSR_BE_BIT, 5; \ - ;; \ - extr.u r30=r16, IA64_PSR_RI_BIT, 2; \ - ;; \ - dep r7=r30, r7, IA64_PSR_RI_BIT, 2; \ - ;; \ - st8 [r22]=r7; \ - ;; - - - -#define IA64_CURRENT_REG IA64_KR(CURRENT) /* r21 is reserved for current pointer */ -//#define VMX_MINSTATE_GET_CURRENT(reg) mov reg=IA64_CURRENT_REG -#define VMX_MINSTATE_GET_CURRENT(reg) mov reg=r21 - -/* - * VMX_DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves - * the minimum state necessary that allows us to turn psr.ic back - * on. - * - * Assumed state upon entry: - * psr.ic: off - * r31: contains saved predicates (pr) - * - * Upon exit, the state is as follows: - * psr.ic: off - * r2 = points to &pt_regs.r16 - * r8 = contents of ar.ccv - * r9 = contents of ar.csd - * r10 = contents of ar.ssd - * r11 = FPSR_DEFAULT - * r12 = kernel sp (kernel virtual address) - * r13 = points to current task_struct (kernel virtual address) - * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: - * preserved - * - * Note that psr.ic is NOT turned on by this macro. This is so that - * we can pass interruption state as arguments to a handler. - */ -#define VMX_DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ -/* switch rr7 */ \ - movl r16=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)); \ - movl r17=(7<<61); \ - movl r20=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)); \ - movl r22=(6<<61); \ - movl r18=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1); \ - movl r23=(5<<61); \ - ;; \ - mov rr[r17]=r16; \ - mov rr[r22]=r20; \ - mov rr[r23]=r18; \ - ;; \ - srlz.i; \ - ;; \ - VMX_MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ - mov r27=ar.rsc; /* M */ \ - mov r20=r1; /* A */ \ - mov r26=ar.unat; /* M */ \ - mov r29=cr.ipsr; /* M */ \ - mov r18=cr.isr; \ - COVER; /* B;; (or nothing) */ \ - ;; \ - tbit.z p6,p0=r29,IA64_PSR_VM_BIT; \ - tbit.nz.or p6,p0 = r18,39; \ - ;; \ -(p6) br.sptk.few vmx_panic; \ - tbit.z p0,p15=r29,IA64_PSR_I_BIT; \ - mov r1=r16; \ -/* mov r21=r16; */ \ - /* switch from user to kernel RBS: */ \ - ;; \ - invala; /* M */ \ - SAVE_IFS; \ - ;; \ - VMX_MINSTATE_START_SAVE_MIN \ - adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ - adds r16=PT(CR_IPSR),r1; \ - ;; \ - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ - st8 [r16]=r29; /* save cr.ipsr */ \ - ;; \ - lfetch.fault.excl.nt1 [r17]; \ - tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ - mov r29=b0 \ - ;; \ - adds r16=PT(R8),r1; /* initialize first base pointer */ \ - adds r17=PT(R9),r1; /* initialize second base pointer */ \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r8,16; \ -.mem.offset 8,0; st8.spill [r17]=r9,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r10,24; \ -.mem.offset 8,0; st8.spill [r17]=r11,24; \ - ;; \ - mov r8=ar.pfs; /* I */ \ - mov r9=cr.iip; /* M */ \ - mov r10=ar.fpsr; /* M */ \ - ;; \ - st8 [r16]=r9,16; /* save cr.iip */ \ - st8 [r17]=r30,16; /* save cr.ifs */ \ - sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ - ;; \ - st8 [r16]=r26,16; /* save ar.unat */ \ - st8 [r17]=r8,16; /* save ar.pfs */ \ - shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ - ;; \ - st8 [r16]=r27,16; /* save ar.rsc */ \ - st8 [r17]=r28,16; /* save ar.rnat */ \ - ;; /* avoid RAW on r16 & r17 */ \ - st8 [r16]=r23,16; /* save ar.bspstore */ \ - st8 [r17]=r31,16; /* save predicates */ \ - ;; \ - st8 [r16]=r29,16; /* save b0 */ \ - st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ -.mem.offset 8,0; st8.spill [r17]=r12,16; \ - adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r13,16; \ -.mem.offset 8,0; st8.spill [r17]=r10,16; /* save ar.fpsr */ \ - mov r13=r21; /* establish `current' */ \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r15,16; \ -.mem.offset 8,0; st8.spill [r17]=r14,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r16]=r2,16; \ -.mem.offset 8,0; st8.spill [r17]=r3,16; \ - adds r2=PT(F6),r1; \ - ;; \ - .mem.offset 0,0; st8.spill [r16]=r4,16; \ - .mem.offset 8,0; st8.spill [r17]=r5,16; \ - ;; \ - .mem.offset 0,0; st8.spill [r16]=r6,16; \ - .mem.offset 8,0; st8.spill [r17]=r7,16; \ - mov r20=ar.ccv; \ - ;; \ - mov r18=cr.iipa; \ - mov r4=cr.isr; \ - mov r22=ar.unat; \ - ;; \ - st8 [r16]=r18,16; \ - st8 [r17]=r4; \ - ;; \ - adds r16=PT(EML_UNAT),r1; \ - adds r17=PT(AR_CCV),r1; \ - ;; \ - st8 [r16]=r22,8; \ - st8 [r17]=r20; \ - mov r4=r24; \ - mov r5=r25; \ - ;; \ - st8 [r16]=r0; \ - EXTRA; \ - mov r9=ar.csd; \ - mov r10=ar.ssd; \ - movl r11=FPSR_DEFAULT; /* L-unit */ \ - movl r1=__gp; /* establish kernel global pointer */ \ - ;; \ - PAL_VSA_SYNC_READ_CLEANUP_PSR_PL \ - VMX_MINSTATE_END_SAVE_MIN - -/* - * SAVE_REST saves the remainder of pt_regs (with psr.ic on). - * - * Assumed state upon entry: - * psr.ic: on - * r2: points to &pt_regs.f6 - * r3: points to &pt_regs.f7 - * r4,r5,scrach - * r6: points to vpd - * r7: vpsr - * r9: contents of ar.csd - * r10: contents of ar.ssd - * r11: FPSR_DEFAULT - * - * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. - */ -#define VMX_SAVE_REST \ - tbit.z pBN0,pBN1=r7,IA64_PSR_BN_BIT; /* guest bank0 or bank1 ? */ \ - ;; \ -(pBN0) add r4=VPD(VBGR),r6; \ -(pBN0) add r5=VPD(VBGR)+0x8,r6; \ -(pBN0) add r7=VPD(VBNAT),r6; \ - ;; \ -(pBN1) add r5=VPD(VGR)+0x8,r6; \ -(pBN1) add r4=VPD(VGR),r6; \ -(pBN1) add r7=VPD(VNAT),r6; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r16,16; \ -.mem.offset 8,0; st8.spill [r5]=r17,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r18,16; \ -.mem.offset 8,0; st8.spill [r5]=r19,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r20,16; \ -.mem.offset 8,0; st8.spill [r5]=r21,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r22,16; \ -.mem.offset 8,0; st8.spill [r5]=r23,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r24,16; \ -.mem.offset 8,0; st8.spill [r5]=r25,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r26,16; \ -.mem.offset 8,0; st8.spill [r5]=r27,16; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r28,16; \ -.mem.offset 8,0; st8.spill [r5]=r29,16; \ - mov r26=b6; \ - ;; \ -.mem.offset 0,0; st8.spill [r4]=r30,16; \ -.mem.offset 8,0; st8.spill [r5]=r31,16; \ - mov r27=b7; \ - ;; \ - mov r30=ar.unat; \ - ;; \ - st8 [r7]=r30; \ - mov ar.fpsr=r11; /* M-unit */ \ - ;; \ - stf.spill [r2]=f6,32; \ - stf.spill [r3]=f7,32; \ - ;; \ - stf.spill [r2]=f8,32; \ - stf.spill [r3]=f9,32; \ - ;; \ - stf.spill [r2]=f10; \ - stf.spill [r3]=f11; \ - ;; \ - adds r2=PT(B6)-PT(F10),r2; \ - adds r3=PT(B7)-PT(F11),r3; \ - ;; \ - st8 [r2]=r26,16; /* b6 */ \ - st8 [r3]=r27,16; /* b7 */ \ - ;; \ - st8 [r2]=r9; /* ar.csd */ \ - st8 [r3]=r10; /* ar.ssd */ \ - ;; - -#define VMX_SAVE_MIN_WITH_COVER VMX_DO_SAVE_MIN(cover, mov r30=cr.ifs,) -#define VMX_SAVE_MIN_WITH_COVER_R19 VMX_DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19) -#define VMX_SAVE_MIN VMX_DO_SAVE_MIN( , mov r30=r0, ) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_phy_mode.c --- a/xen/arch/ia64/vmx_phy_mode.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,433 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_phy_mode.c: emulating domain physical mode. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Arun Sharma (arun.sharma@xxxxxxxxx) - * Kun Tian (Kevin Tian) (kevin.tian@xxxxxxxxx) - * Xuefei Xu (Anthony Xu) (anthony.xu@xxxxxxxxx) - */ - - -#include <asm/processor.h> -#include <asm/gcc_intrin.h> -#include <asm/vmx_phy_mode.h> -#include <xen/sched.h> -#include <asm/pgtable.h> - - -int valid_mm_mode[8] = { - GUEST_PHYS, /* (it, dt, rt) -> (0, 0, 0) */ - INV_MODE, - INV_MODE, - GUEST_PHYS, /* (it, dt, rt) -> (0, 1, 1) */ - INV_MODE, - GUEST_PHYS, /* (it, dt, rt) -> (1, 0, 1) */ - INV_MODE, - GUEST_VIRT, /* (it, dt, rt) -> (1, 1, 1).*/ -}; - -/* - * Special notes: - * - Index by it/dt/rt sequence - * - Only existing mode transitions are allowed in this table - * - RSE is placed at lazy mode when emulating guest partial mode - * - If gva happens to be rr0 and rr4, only allowed case is identity - * mapping (gva=gpa), or panic! (How?) - */ -int mm_switch_table[8][8] = { - /* 2004/09/12(Kevin): Allow switch to self */ - /* - * (it,dt,rt): (0,0,0) -> (1,1,1) - * This kind of transition usually occurs in the very early - * stage of Linux boot up procedure. Another case is in efi - * and pal calls. (see "arch/ia64/kernel/head.S") - * - * (it,dt,rt): (0,0,0) -> (0,1,1) - * This kind of transition is found when OSYa exits efi boot - * service. Due to gva = gpa in this case (Same region), - * data access can be satisfied though itlb entry for physical - * emulation is hit. - */ - SW_SELF,0, 0, SW_NOP, 0, 0, 0, SW_P2V, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* - * (it,dt,rt): (0,1,1) -> (1,1,1) - * This kind of transition is found in OSYa. - * - * (it,dt,rt): (0,1,1) -> (0,0,0) - * This kind of transition is found in OSYa - */ - SW_NOP, 0, 0, SW_SELF,0, 0, 0, SW_P2V, - /* (1,0,0)->(1,1,1) */ - 0, 0, 0, 0, 0, 0, 0, SW_P2V, - /* - * (it,dt,rt): (1,0,1) -> (1,1,1) - * This kind of transition usually occurs when Linux returns - * from the low level TLB miss handlers. - * (see "arch/ia64/kernel/ivt.S") - */ - 0, 0, 0, 0, 0, SW_SELF,0, SW_P2V, - 0, 0, 0, 0, 0, 0, 0, 0, - /* - * (it,dt,rt): (1,1,1) -> (1,0,1) - * This kind of transition usually occurs in Linux low level - * TLB miss handler. (see "arch/ia64/kernel/ivt.S") - * - * (it,dt,rt): (1,1,1) -> (0,0,0) - * This kind of transition usually occurs in pal and efi calls, - * which requires running in physical mode. - * (see "arch/ia64/kernel/head.S") - * (1,1,1)->(1,0,0) - */ - - SW_V2P, 0, 0, 0, SW_V2P, SW_V2P, 0, SW_SELF, -}; - -void -physical_mode_init(VCPU *vcpu) -{ - UINT64 psr; - struct domain * d = vcpu->domain; - - vcpu->arch.old_rsc = 0; - vcpu->arch.mode_flags = GUEST_IN_PHY; -} - -extern u64 get_mfn(domid_t domid, u64 gpfn, u64 pages); -#if 0 -void -physical_itlb_miss_domn(VCPU *vcpu, u64 vadr) -{ - u64 psr; - IA64_PSR vpsr; - u64 mppn,gppn,mpp1,gpp1; - struct domain *d; - static u64 test=0; - d=vcpu->domain; - if(test) - panic("domn physical itlb miss happen\n"); - else - test=1; - vpsr.val=vmx_vcpu_get_psr(vcpu); - gppn=(vadr<<1)>>13; - mppn = get_mfn(DOMID_SELF,gppn,1); - mppn=(mppn<<12)|(vpsr.cpl<<7); - gpp1=0; - mpp1 = get_mfn(DOMID_SELF,gpp1,1); - mpp1=(mpp1<<12)|(vpsr.cpl<<7); -// if(vadr>>63) -// mppn |= PHY_PAGE_UC; -// else -// mppn |= PHY_PAGE_WB; - mpp1 |= PHY_PAGE_WB; - psr=ia64_clear_ic(); - ia64_itr(0x1, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); - ia64_srlz_i(); - ia64_itr(0x2, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); - ia64_stop(); - ia64_srlz_i(); - ia64_itr(0x1, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); - ia64_srlz_i(); - ia64_itr(0x2, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); - ia64_stop(); - ia64_srlz_i(); - ia64_itr(0x1, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); - ia64_srlz_i(); - ia64_itr(0x2, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); - ia64_stop(); - ia64_srlz_i(); - ia64_set_psr(psr); - ia64_srlz_i(); - return; -} -#endif - -void -physical_itlb_miss(VCPU *vcpu, u64 vadr) -{ - physical_itlb_miss_dom0(vcpu, vadr); -} - - -void -physical_itlb_miss_dom0(VCPU *vcpu, u64 vadr) -{ - u64 psr; - IA64_PSR vpsr; - u64 mppn,gppn; - vpsr.val=vmx_vcpu_get_psr(vcpu); - gppn=(vadr<<1)>>13; - mppn = get_mfn(DOMID_SELF,gppn,1); - mppn=(mppn<<12)|(vpsr.cpl<<7); -// if(vadr>>63) -// mppn |= PHY_PAGE_UC; -// else - mppn |= PHY_PAGE_WB; - - psr=ia64_clear_ic(); - ia64_itc(1,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); - ia64_set_psr(psr); - ia64_srlz_i(); - return; -} - - -void -physical_dtlb_miss(VCPU *vcpu, u64 vadr) -{ - u64 psr; - IA64_PSR vpsr; - u64 mppn,gppn; -// if(vcpu->domain!=dom0) -// panic("dom n physical dtlb miss happen\n"); - vpsr.val=vmx_vcpu_get_psr(vcpu); - gppn=(vadr<<1)>>13; - mppn = get_mfn(DOMID_SELF,gppn,1); - mppn=(mppn<<12)|(vpsr.cpl<<7); - if(vadr>>63) - mppn |= PHY_PAGE_UC; - else - mppn |= PHY_PAGE_WB; - - psr=ia64_clear_ic(); - ia64_itc(2,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); - ia64_set_psr(psr); - ia64_srlz_i(); - return; -} - -void -vmx_init_all_rr(VCPU *vcpu) -{ - VMX(vcpu,vrr[VRN0]) = 0x38; - VMX(vcpu,vrr[VRN1]) = 0x38; - VMX(vcpu,vrr[VRN2]) = 0x38; - VMX(vcpu,vrr[VRN3]) = 0x38; - VMX(vcpu,vrr[VRN4]) = 0x38; - VMX(vcpu,vrr[VRN5]) = 0x38; - VMX(vcpu,vrr[VRN6]) = 0x60; - VMX(vcpu,vrr[VRN7]) = 0x60; - - VMX(vcpu,mrr5) = vmx_vrrtomrr(vcpu, 0x38); - VMX(vcpu,mrr6) = vmx_vrrtomrr(vcpu, 0x60); - VMX(vcpu,mrr7) = vmx_vrrtomrr(vcpu, 0x60); -} - -void -vmx_load_all_rr(VCPU *vcpu) -{ - unsigned long psr; - ia64_rr phy_rr; - - psr = ia64_clear_ic(); - - phy_rr.ps = EMUL_PHY_PAGE_SHIFT; - phy_rr.ve = 1; - - /* WARNING: not allow co-exist of both virtual mode and physical - * mode in same region - */ - if (is_physical_mode(vcpu)) { - if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) - panic("Unexpected domain switch in phy emul\n"); - phy_rr.rid = vcpu->domain->arch.metaphysical_rr0; - ia64_set_rr((VRN0 << VRN_SHIFT), phy_rr.rrval); - phy_rr.rid = vcpu->domain->arch.metaphysical_rr4; - ia64_set_rr((VRN4 << VRN_SHIFT), phy_rr.rrval); - } else { - ia64_set_rr((VRN0 << VRN_SHIFT), - vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN0]))); - ia64_set_rr((VRN4 << VRN_SHIFT), - vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN4]))); - } - -#if 1 - /* rr567 will be postponed to last point when resuming back to guest */ - ia64_set_rr((VRN1 << VRN_SHIFT), - vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN1]))); - ia64_set_rr((VRN2 << VRN_SHIFT), - vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN2]))); - ia64_set_rr((VRN3 << VRN_SHIFT), - vmx_vrrtomrr(vcpu, VMX(vcpu, vrr[VRN3]))); -#endif - ia64_srlz_d(); - ia64_set_psr(psr); - ia64_srlz_i(); -} - -void -switch_to_physical_rid(VCPU *vcpu) -{ - UINT64 psr; - ia64_rr phy_rr; - - phy_rr.ps = EMUL_PHY_PAGE_SHIFT; - phy_rr.ve = 1; - - /* Save original virtual mode rr[0] and rr[4] */ - psr=ia64_clear_ic(); - phy_rr.rid = vcpu->domain->arch.metaphysical_rr0; - ia64_set_rr(VRN0<<VRN_SHIFT, phy_rr.rrval); - ia64_srlz_d(); - phy_rr.rid = vcpu->domain->arch.metaphysical_rr4; - ia64_set_rr(VRN4<<VRN_SHIFT, phy_rr.rrval); - ia64_srlz_d(); - - ia64_set_psr(psr); - ia64_srlz_i(); - return; -} - - -void -switch_to_virtual_rid(VCPU *vcpu) -{ - UINT64 psr; - ia64_rr mrr; - - psr=ia64_clear_ic(); - - mrr=vmx_vcpu_rr(vcpu,VRN0<<VRN_SHIFT); - ia64_set_rr(VRN0<<VRN_SHIFT, vmx_vrrtomrr(vcpu, mrr.rrval)); - ia64_srlz_d(); - mrr=vmx_vcpu_rr(vcpu,VRN4<<VRN_SHIFT); - ia64_set_rr(VRN4<<VRN_SHIFT, vmx_vrrtomrr(vcpu, mrr.rrval)); - ia64_srlz_d(); - ia64_set_psr(psr); - ia64_srlz_i(); - return; -} - -static int mm_switch_action(IA64_PSR opsr, IA64_PSR npsr) -{ - return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)]; -} - -void -switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr) -{ - int act; - REGS * regs=vcpu_regs(vcpu); - act = mm_switch_action(old_psr, new_psr); - switch (act) { - case SW_V2P: - vcpu->arch.old_rsc = regs->ar_rsc; - switch_to_physical_rid(vcpu); - /* - * Set rse to enforced lazy, to prevent active rse save/restor when - * guest physical mode. - */ - regs->ar_rsc &= ~(IA64_RSC_MODE); - vcpu->arch.mode_flags |= GUEST_IN_PHY; - break; - case SW_P2V: - switch_to_virtual_rid(vcpu); - /* - * recover old mode which is saved when entering - * guest physical mode - */ - regs->ar_rsc = vcpu->arch.old_rsc; - vcpu->arch.mode_flags &= ~GUEST_IN_PHY; - break; - case SW_SELF: - printf("Switch to self-0x%lx!!! MM mode doesn't change...\n", - old_psr.val); - break; - case SW_NOP: - printf("No action required for mode transition: (0x%lx -> 0x%lx)\n", - old_psr.val, new_psr.val); - break; - default: - /* Sanity check */ - printf("old: %lx, new: %lx\n", old_psr.val, new_psr.val); - panic("Unexpected virtual <--> physical mode transition"); - break; - } - return; -} - - - -/* - * In physical mode, insert tc/tr for region 0 and 4 uses - * RID[0] and RID[4] which is for physical mode emulation. - * However what those inserted tc/tr wants is rid for - * virtual mode. So original virtual rid needs to be restored - * before insert. - * - * Operations which required such switch include: - * - insertions (itc.*, itr.*) - * - purges (ptc.* and ptr.*) - * - tpa - * - tak - * - thash?, ttag? - * All above needs actual virtual rid for destination entry. - */ - -void -check_mm_mode_switch (VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr) -{ - - if ( (old_psr.dt != new_psr.dt ) || - (old_psr.it != new_psr.it ) || - (old_psr.rt != new_psr.rt ) - ) { - switch_mm_mode (vcpu, old_psr, new_psr); - } - - return 0; -} - - -/* - * In physical mode, insert tc/tr for region 0 and 4 uses - * RID[0] and RID[4] which is for physical mode emulation. - * However what those inserted tc/tr wants is rid for - * virtual mode. So original virtual rid needs to be restored - * before insert. - * - * Operations which required such switch include: - * - insertions (itc.*, itr.*) - * - purges (ptc.* and ptr.*) - * - tpa - * - tak - * - thash?, ttag? - * All above needs actual virtual rid for destination entry. - */ - -void -prepare_if_physical_mode(VCPU *vcpu) -{ - if (is_physical_mode(vcpu)) { - vcpu->arch.mode_flags |= GUEST_PHY_EMUL; - switch_to_virtual_rid(vcpu); - } - return; -} - -/* Recover always follows prepare */ -void -recover_if_physical_mode(VCPU *vcpu) -{ - if (is_physical_mode(vcpu)) { - vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; - switch_to_physical_rid(vcpu); - } - return; -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_process.c --- a/xen/arch/ia64/vmx_process.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,375 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_process.c: handling VMX architecture-related VM exits - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/errno.h> -#include <xen/sched.h> -#include <xen/smp.h> -#include <asm/ptrace.h> -#include <xen/delay.h> - -#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */ -#include <asm/sal.h> /* FOR struct ia64_sal_retval */ - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/desc.h> -//#include <asm/ldt.h> -#include <xen/irq.h> -#include <xen/event.h> -#include <asm/regionreg.h> -#include <asm/privop.h> -#include <asm/ia64_int.h> -#include <asm/hpsim_ssc.h> -#include <asm/dom_fw.h> -#include <asm/vmx_vcpu.h> -#include <asm/kregs.h> -#include <asm/vmx.h> -#include <asm/vmx_mm_def.h> -#include <xen/mm.h> -/* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ -#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 - - -extern struct ia64_sal_retval pal_emulator_static(UINT64); -extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); -extern void rnat_consumption (VCPU *vcpu); -#define DOMN_PAL_REQUEST 0x110000 -IA64FAULT -vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) -{ - static int first_time = 1; - struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; - extern unsigned long running_on_sim; - unsigned long i, sal_param[8]; - -#if 0 - if (first_time) { - if (platform_is_hp_ski()) running_on_sim = 1; - else running_on_sim = 0; - first_time = 0; - } - if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant - if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); - else do_ssc(vcpu_get_gr(current,36), regs); - } -#endif - if (iim == d->arch.breakimm) { - struct ia64_sal_retval x; - switch (regs->r2) { - case FW_HYPERCALL_PAL_CALL: - //printf("*** PAL hypercall: index=%d\n",regs->r28); - //FIXME: This should call a C routine - x = pal_emulator_static(VMX_VPD(v, vgr[12])); - regs->r8 = x.status; regs->r9 = x.v0; - regs->r10 = x.v1; regs->r11 = x.v2; -#if 0 - if (regs->r8) - printk("Failed vpal emulation, with index:0x%lx\n", - VMX_VPD(v, vgr[12])); -#endif - break; - case FW_HYPERCALL_SAL_CALL: - for (i = 0; i < 8; i++) - vmx_vcpu_get_gr(v, 32+i, &sal_param[i]); - x = sal_emulator(sal_param[0], sal_param[1], - sal_param[2], sal_param[3], - sal_param[4], sal_param[5], - sal_param[6], sal_param[7]); - regs->r8 = x.status; regs->r9 = x.v0; - regs->r10 = x.v1; regs->r11 = x.v2; -#if 0 - if (regs->r8) - printk("Failed vsal emulation, with index:0x%lx\n", - sal_param[0]); -#endif - break; - case FW_HYPERCALL_EFI_RESET_SYSTEM: - printf("efi.reset_system called "); - if (current->domain == dom0) { - printf("(by dom0)\n "); - (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL); - } - printf("(not supported for non-0 domain)\n"); - regs->r8 = EFI_UNSUPPORTED; - break; - case FW_HYPERCALL_EFI_GET_TIME: - { - unsigned long *tv, *tc; - vmx_vcpu_get_gr(v, 32, &tv); - vmx_vcpu_get_gr(v, 33, &tc); - printf("efi_get_time(%p,%p) called...",tv,tc); - tv = __va(translate_domain_mpaddr(tv)); - if (tc) tc = __va(translate_domain_mpaddr(tc)); - regs->r8 = (*efi.get_time)(tv,tc); - printf("and returns %lx\n",regs->r8); - } - break; - case FW_HYPERCALL_EFI_SET_TIME: - case FW_HYPERCALL_EFI_GET_WAKEUP_TIME: - case FW_HYPERCALL_EFI_SET_WAKEUP_TIME: - // FIXME: need fixes in efi.h from 2.6.9 - case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP: - // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED - // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS - // POINTER ARGUMENTS WILL BE VIRTUAL!! - case FW_HYPERCALL_EFI_GET_VARIABLE: - // FIXME: need fixes in efi.h from 2.6.9 - case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE: - case FW_HYPERCALL_EFI_SET_VARIABLE: - case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT: - // FIXME: need fixes in efi.h from 2.6.9 - regs->r8 = EFI_UNSUPPORTED; - break; - } -#if 0 - if (regs->r8) - printk("Failed vgfw emulation, with index:0x%lx\n", - regs->r2); -#endif - vmx_vcpu_increment_iip(current); - }else if(iim == DOMN_PAL_REQUEST){ - pal_emul(current); - vmx_vcpu_increment_iip(current); - } else - vmx_reflect_interruption(ifa,isr,iim,11); -} - -static UINT64 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, - 0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700,0x6800,0x6900,0x6a00, - 0x6b00,0x6c00,0x6d00,0x6e00,0x6f00,0x7000,0x7100,0x7200,0x7300,0x7400, - 0x7500,0x7600,0x7700,0x7800,0x7900,0x7a00,0x7b00,0x7c00,0x7d00,0x7e00, - 0x7f00, -}; - - - -void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, - UINT64 vector) -{ - VCPU *vcpu = current; - REGS *regs=vcpu_regs(vcpu); - UINT64 viha,vpsr = vmx_vcpu_get_psr(vcpu); - if(!(vpsr&IA64_PSR_IC)&&(vector!=5)){ - panic("Guest nested fault!"); - } - VPD_CR(vcpu,isr)=isr; - VPD_CR(vcpu,iipa) = regs->cr_iip; - vector=vec2off[vector]; - if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) - VPD_CR(vcpu,iim) = iim; - else { - set_ifa_itir_iha(vcpu,ifa,1,1,1); - } - inject_guest_interruption(vcpu, vector); -} - -// ONLY gets called from ia64_leave_kernel -// ONLY call with interrupts disabled?? (else might miss one?) -// NEVER successful if already reflecting a trap/fault because psr.i==0 -void leave_hypervisor_tail(struct pt_regs *regs) -{ - struct domain *d = current->domain; - struct vcpu *v = current; - // FIXME: Will this work properly if doing an RFI??? - if (!is_idle_task(d) ) { // always comes from guest - extern void vmx_dorfirfi(void); - struct pt_regs *user_regs = vcpu_regs(current); - - if (local_softirq_pending()) - do_softirq(); - local_irq_disable(); - - if (user_regs != regs) - printk("WARNING: checking pending interrupt in nested interrupt!!!\n"); - - /* VMX Domain N has other interrupt source, saying DM */ - if (test_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags)) - vmx_intr_assist(v); - - /* FIXME: Check event pending indicator, and set - * pending bit if necessary to inject back to guest. - * Should be careful about window between this check - * and above assist, since IOPACKET_PORT shouldn't be - * injected into vmx domain. - * - * Now hardcode the vector as 0x10 temporarily - */ - if (event_pending(v)&&(!((v->arch.arch_vmx.in_service[0])&(1UL<<0x10)))) { - VPD_CR(v, irr[0]) |= 1UL << 0x10; - v->arch.irq_new_pending = 1; - } - - if ( v->arch.irq_new_pending ) { - v->arch.irq_new_pending = 0; - vmx_check_pending_irq(v); - } - } -} - -extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); - -/* We came here because the H/W VHPT walker failed to find an entry */ -void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) -{ - IA64_PSR vpsr; - CACHE_LINE_TYPE type; - u64 vhpt_adr; - ISR misr; - ia64_rr vrr; - REGS *regs; - thash_cb_t *vtlb, *vhpt; - thash_data_t *data, me; - vtlb=vmx_vcpu_get_vtlb(vcpu); -#ifdef VTLB_DEBUG - check_vtlb_sanity(vtlb); - dump_vtlb(vtlb); -#endif - vpsr.val = vmx_vcpu_get_psr(vcpu); - regs = vcpu_regs(vcpu); - misr.val=regs->cr_isr; -/* TODO - if(vcpu->domain->id && vec == 2 && - vpsr.dt == 0 && is_gpa_io(MASK_PMA(vaddr))){ - emulate_ins(&v); - return; - } -*/ - - if((vec==1)&&(!vpsr.it)){ - physical_itlb_miss(vcpu, vadr); - return; - } - if((vec==2)&&(!vpsr.dt)){ - if(vcpu->domain!=dom0&&__gpfn_is_io(vcpu->domain,(vadr<<1)>>(PAGE_SHIFT+1))){ - emulate_io_inst(vcpu,((vadr<<1)>>1),4); // UC - }else{ - physical_dtlb_miss(vcpu, vadr); - } - return; - } - vrr = vmx_vcpu_rr(vcpu,vadr); - if(vec == 1) type = ISIDE_TLB; - else if(vec == 2) type = DSIDE_TLB; - else panic("wrong vec\n"); - -// prepare_if_physical_mode(vcpu); - - if(data=vtlb_lookup_ex(vtlb, vrr.rid, vadr,type)){ - if(vcpu->domain!=dom0&&type==DSIDE_TLB && __gpfn_is_io(vcpu->domain, data->ppn>>(PAGE_SHIFT-12))){ - vadr=(vadr&((1UL<<data->ps)-1))+(data->ppn>>(data->ps-12)<<data->ps); - emulate_io_inst(vcpu, vadr, data->ma); - return IA64_FAULT; - } - if ( data->ps != vrr.ps ) { - machine_tlb_insert(vcpu, data); - } - else { - thash_insert(vtlb->ts->vhpt,data,vadr); - } - }else if(type == DSIDE_TLB){ - if(!vhpt_enabled(vcpu, vadr, misr.rs?RSE_REF:DATA_REF)){ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, misr.val); - alt_dtlb(vcpu, vadr); - return IA64_FAULT; - } else{ - if(misr.sp){ - //TODO lds emulation - panic("Don't support speculation load"); - }else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - } else{ - vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); - vrr=vmx_vcpu_rr(vcpu,vhpt_adr); - data = vtlb_lookup_ex(vtlb, vrr.rid, vhpt_adr, DSIDE_TLB); - if(data){ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, misr.val); - dtlb_fault(vcpu, vadr); - return IA64_FAULT; - }else{ - if(misr.sp){ - //TODO lds emulation - panic("Don't support speculation load"); - }else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - }else{ - if(vpsr.ic){ - vmx_vcpu_set_isr(vcpu, misr.val); - dvhpt_fault(vcpu, vadr); - return IA64_FAULT; - }else{ - if(misr.sp){ - //TODO lds emulation - panic("Don't support speculation load"); - }else{ - nested_dtlb(vcpu); - return IA64_FAULT; - } - } - } - } - }else if(type == ISIDE_TLB){ - if(!vhpt_enabled(vcpu, vadr, misr.rs?RSE_REF:DATA_REF)){ - if(!vpsr.ic){ - misr.ni=1; - } - vmx_vcpu_set_isr(vcpu, misr.val); - alt_itlb(vcpu, vadr); - return IA64_FAULT; - } else{ - vmx_vcpu_thash(vcpu, vadr, &vhpt_adr); - vrr=vmx_vcpu_rr(vcpu,vhpt_adr); - data = vtlb_lookup_ex(vtlb, vrr.rid, vhpt_adr, DSIDE_TLB); - if(data){ - if(!vpsr.ic){ - misr.ni=1; - } - vmx_vcpu_set_isr(vcpu, misr.val); - itlb_fault(vcpu, vadr); - return IA64_FAULT; - }else{ - if(!vpsr.ic){ - misr.ni=1; - } - vmx_vcpu_set_isr(vcpu, misr.val); - ivhpt_fault(vcpu, vadr); - return IA64_FAULT; - } - } - } -} - - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_support.c --- a/xen/arch/ia64/vmx_support.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,164 +0,0 @@ - -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_support.c: vmx specific support interface. - * Copyright (c) 2005, Intel Corporation. - * Kun Tian (Kevin Tian) (Kevin.tian@xxxxxxxxx) - * - * 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. - * - */ -#include <xen/config.h> -#include <xen/sched.h> -#include <public/io/ioreq.h> -#include <asm/vmx.h> -#include <asm/vmx_vcpu.h> - -/* - * I/O emulation should be atomic from domain point of view. However, - * when emulation code is waiting for I/O completion by do_block, - * other events like DM interrupt, VBD, etc. may come and unblock - * current exection flow. So we have to prepare for re-block if unblocked - * by non I/O completion event. - */ -void vmx_wait_io(void) -{ - struct vcpu *v = current; - struct domain *d = v->domain; - extern void do_block(); - int port = iopacket_port(d); - - do { - if (!test_bit(port, - &d->shared_info->evtchn_pending[0])) - do_block(); - - /* Unblocked when some event is coming. Clear pending indication - * immediately if deciding to go for io assist - */ - if (test_and_clear_bit(port, - &d->shared_info->evtchn_pending[0])) { - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); - clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); - vmx_io_assist(v); - } - - - if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { - /* - * Latest event is not I/O completion, so clear corresponding - * selector and pending indication, to allow real event coming - */ - clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); - - /* Here atually one window is leaved before selector is cleared. - * However this window only delay the indication to coming event, - * nothing losed. Next loop will check I/O channel to fix this - * window. - */ - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); - } - else - break; - } while (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)); -} - -/* - * Only place to call vmx_io_assist is mmio/legacy_io emulation. - * Since I/O emulation is synchronous, it shouldn't be called in - * other places. This is not like x86, since IA-64 implements a - * per-vp stack without continuation. - */ -void vmx_io_assist(struct vcpu *v) -{ - vcpu_iodata_t *vio; - ioreq_t *p; - - /* - * This shared page contains I/O request between emulation code - * and device model. - */ - vio = get_vio(v->domain, v->vcpu_id); - if (!vio) - panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); - - p = &vio->vp_ioreq; - - if (p->state == STATE_IORESP_HOOK) - panic("Not supported: No hook available for DM request\n"); - - if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { - if (p->state != STATE_IORESP_READY) { - /* Can't do_block here, for the same reason as other places to - * use vmx_wait_io. Simple return is safe since vmx_wait_io will - * try to block again - */ - return; - } else - p->state = STATE_INVALID; - - clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); - } else - return; /* Spurous event? */ -} - -/* - * VMX domainN has two types of interrupt source: lsapic model within - * HV, and device model within domain 0 (service OS). There're another - * pending array in share page, manipulated by device model directly. - * To conform to VT-i spec, we have to sync pending bits in shared page - * into VPD. This has to be done before checking pending interrupt at - * resume to guest. For domain 0, all the interrupt sources come from - * HV, which then doesn't require this assist. - */ -void vmx_intr_assist(struct vcpu *v) -{ - vcpu_iodata_t *vio; - struct domain *d = v->domain; - extern void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, - unsigned long *pend_irr); - int port = iopacket_port(d); - - /* I/O emulation is atomic, so it's impossible to see execution flow - * out of vmx_wait_io, when guest is still waiting for response. - */ - if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) - panic("!!!Bad resume to guest before I/O emulation is done.\n"); - - /* Clear indicator specific to interrupt delivered from DM */ - if (test_and_clear_bit(port, - &d->shared_info->evtchn_pending[0])) { - if (!d->shared_info->evtchn_pending[port >> 5]) - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); - - if (!v->vcpu_info->evtchn_pending_sel) - clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); - } - - /* Even without event pending, we still need to sync pending bits - * between DM and vlsapic. The reason is that interrupt delivery - * shares same event channel as I/O emulation, with corresponding - * indicator possibly cleared when vmx_wait_io(). - */ - vio = get_vio(v->domain, v->vcpu_id); - if (!vio) - panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); - -#ifdef V_IOSAPIC_READY - vlapic_update_ext_irq(v); -#else - panic("IOSAPIC model is missed in qemu\n"); -#endif - return; -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_utility.c --- a/xen/arch/ia64/vmx_utility.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,659 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_utility.c: - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> - * Xiaoyan Feng (Fleming Feng) <fleming.feng@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <xen/types.h> -#include <asm/vmx_vcpu.h> -#include <asm/processor.h> -#include <asm/vmx_mm_def.h> - - -/* - * Return: - * 0: Not reserved indirect registers - * 1: Is reserved indirect registers - */ -int -is_reserved_indirect_register ( - int type, - int index ) -{ - switch (type) { - case IA64_CPUID: - if ( index >= 5 ) { - return 1; - } - - case IA64_DBR: - case IA64_IBR: - //bugbugbug:check with pal about the max ibr/dbr!!!! - break; - - case IA64_PMC: - //bugbugbug:check with pal about the max ibr/dbr!!!! - break; - - case IA64_PMD: - //bugbugbug:check with pal about the max ibr/dbr!!!! - break; - - case IA64_PKR: - //bugbugbug:check with pal about the max pkr!!!! - break; - - case IA64_RR: - //bugbugbug:check with pal about the max rr!!!! - break; - - default: - panic ("Unsupported instruction!"); - } - - return 0; - -} - -/* - * Return: - * Set all ignored fields in value to 0 and return - */ -u64 -indirect_reg_igfld_MASK ( - int type, - int index, - u64 value - ) -{ - u64 nvalue; - - nvalue = value; - switch ( type ) { - case IA64_CPUID: - if ( index == 2 ) { - nvalue = 0; - } - break; - - case IA64_DBR: - case IA64_IBR: - /* Refer to SDM Vol2 Table 7-1,7-2 */ - if ( index % 2 != 0) { - /* Ignore field: {61:60} */ - nvalue = value & (~MASK (60, 2)); - } - break; - case IA64_PMC: - if ( index == 0 ) { - /* Ignore field: 3:1 */ - nvalue = value & (~MASK (1, 3)); - } - break; - case IA64_PMD: - if ( index >= 4 ) { - /* Ignore field: 7:7 */ - /* bugbug: this code is correct for generic - * PMD. However, for implementation specific - * PMD, it's WRONG. need more info to judge - * what's implementation specific PMD. - */ - nvalue = value & (~MASK (7, 1)); - } - break; - case IA64_PKR: - case IA64_RR: - break; - default: - panic ("Unsupported instruction!"); - } - - return nvalue; -} - -/* - * Return: - * Set all ignored fields in value to 0 and return - */ -u64 -cr_igfld_mask (int index, u64 value) -{ - u64 nvalue; - - nvalue = value; - - switch ( index ) { - case IA64_REG_CR_IVA: - /* Ignore filed: 14:0 */ - nvalue = value & (~MASK (0, 15)); - break; - - case IA64_REG_CR_IHA: - /* Ignore filed: 1:0 */ - nvalue = value & (~MASK (0, 2)); - break; - - case IA64_REG_CR_LID: - /* Ignore filed: 63:32 */ - nvalue = value & (~MASK (32, 32)); - break; - - case IA64_REG_CR_TPR: - /* Ignore filed: 63:17,3:0 */ - nvalue = value & (~MASK (17, 47)); - nvalue = nvalue & (~MASK (0, 4)); - break; - - case IA64_REG_CR_EOI: - /* Ignore filed: 63:0 */ - nvalue = 0; - break; - - case IA64_REG_CR_ITV: - case IA64_REG_CR_PMV: - case IA64_REG_CR_CMCV: - case IA64_REG_CR_LRR0: - case IA64_REG_CR_LRR1: - /* Ignore filed: 63:17,12:12 */ - nvalue = value & (~MASK (17, 47)); - nvalue = nvalue & (~MASK (12, 1)); - break; - } - - return nvalue; -} - - -/* - * Return: - * 1: PSR reserved fields are not zero - * 0: PSR reserved fields are all zero - */ -int -check_psr_rsv_fields (u64 value) -{ - /* PSR reserved fields: 0, 12~6, 16, 31~28, 63~46 - * These reserved fields shall all be zero - * Otherwise we will panic - */ - - if ( value & MASK (0, 1) || - value & MASK (6, 7) || - value & MASK (16, 1) || - value & MASK (28, 4) || - value & MASK (46, 18) - ) { - return 1; - } - - return 0; -} - - - -/* - * Return: - * 1: CR reserved fields are not zero - * 0: CR reserved fields are all zero - */ -int -check_cr_rsv_fields (int index, u64 value) -{ - switch (index) { - case IA64_REG_CR_DCR: - if ( (value & MASK ( 3, 5 )) || - (value & MASK (15, 49))) { - return 1; - } - return 0; - - case IA64_REG_CR_ITM: - case IA64_REG_CR_IVA: - case IA64_REG_CR_IIP: - case IA64_REG_CR_IFA: - case IA64_REG_CR_IIPA: - case IA64_REG_CR_IIM: - case IA64_REG_CR_IHA: - case IA64_REG_CR_EOI: - return 0; - - case IA64_REG_CR_PTA: - if ( (value & MASK ( 1, 1 )) || - (value & MASK (9, 6))) { - return 1; - } - return 0; - - case IA64_REG_CR_IPSR: - return check_psr_rsv_fields (value); - - - case IA64_REG_CR_ISR: - if ( (value & MASK ( 24, 8 )) || - (value & MASK (44, 20))) { - return 1; - } - return 0; - - case IA64_REG_CR_ITIR: - if ( (value & MASK ( 0, 2 )) || - (value & MASK (32, 32))) { - return 1; - } - return 0; - - case IA64_REG_CR_IFS: - if ( (value & MASK ( 38, 25 ))) { - return 1; - } - return 0; - - case IA64_REG_CR_LID: - if ( (value & MASK ( 0, 16 ))) { - return 1; - } - return 0; - - case IA64_REG_CR_IVR: - if ( (value & MASK ( 8, 56 ))) { - return 1; - } - return 0; - - case IA64_REG_CR_TPR: - if ( (value & MASK ( 8, 8 ))) { - return 1; - } - return 0; - - case IA64_REG_CR_IRR0: - if ( (value & MASK ( 1, 1 )) || - (value & MASK (3, 13))) { - return 1; - } - return 0; - - case IA64_REG_CR_ITV: - case IA64_REG_CR_PMV: - case IA64_REG_CR_CMCV: - if ( (value & MASK ( 8, 4 )) || - (value & MASK (13, 3))) { - return 1; - } - return 0; - - case IA64_REG_CR_LRR0: - case IA64_REG_CR_LRR1: - if ( (value & MASK ( 11, 1 )) || - (value & MASK (14, 1))) { - return 1; - } - return 0; - } - - - panic ("Unsupported CR"); -} - - - -/* - * Return: - * 0: Indirect Reg reserved fields are not zero - * 1: Indirect Reg reserved fields are all zero - */ -int -check_indirect_reg_rsv_fields ( int type, int index, u64 value ) -{ - - switch ( type ) { - case IA64_CPUID: - if ( index == 3 ) { - if ( value & MASK (40, 24 )) { - return 0; - } - } else if ( index == 4 ) { - if ( value & MASK (2, 62 )) { - return 0; - } - } - break; - - case IA64_DBR: - case IA64_IBR: - case IA64_PMC: - case IA64_PMD: - break; - - case IA64_PKR: - if ( value & MASK (4, 4) || - value & MASK (32, 32 )) { - return 0; - } - break; - - case IA64_RR: - if ( value & MASK (1, 1) || - value & MASK (32, 32 )) { - return 0; - } - break; - - default: - panic ("Unsupported instruction!"); - } - - return 1; -} - - - - -/* Return - * Same format as isr_t - * Only ei/ni bits are valid, all other bits are zero - */ -u64 -set_isr_ei_ni (VCPU *vcpu) -{ - - IA64_PSR vpsr,ipsr; - ISR visr; - REGS *regs; - - regs=vcpu_regs(vcpu); - - visr.val = 0; - - vpsr.val = vmx_vcpu_get_psr (vcpu); - - if (!vpsr.ic == 1 ) { - /* Set ISR.ni */ - visr.ni = 1; - } - ipsr.val = regs->cr_ipsr; - - visr.ei = ipsr.ri; - return visr.val; -} - - -/* Set up ISR.na/code{3:0}/r/w for no-access instructions - * Refer to SDM Vol Table 5-1 - * Parameter: - * setr: if 1, indicates this function will set up ISR.r - * setw: if 1, indicates this function will set up ISR.w - * Return: - * Same format as ISR. All fields are zero, except na/code{3:0}/r/w - */ -u64 -set_isr_for_na_inst(VCPU *vcpu, int op) -{ - ISR visr; - visr.val = 0; - switch (op) { - case IA64_INST_TPA: - visr.na = 1; - visr.code = 0; - break; - case IA64_INST_TAK: - visr.na = 1; - visr.code = 3; - break; - } - return visr.val; -} - - - -/* - * Set up ISR for registe Nat consumption fault - * Parameters: - * read: if 1, indicates this is a read access; - * write: if 1, indicates this is a write access; - */ -void -set_rnat_consumption_isr (VCPU *vcpu,int inst,int read,int write) -{ - ISR visr; - u64 value; - /* Need set up ISR: code, ei, ni, na, r/w */ - visr.val = 0; - - /* ISR.code{7:4} =1, - * Set up ISR.code{3:0}, ISR.na - */ - visr.code = (1 << 4); - if (inst) { - - value = set_isr_for_na_inst (vcpu,inst); - visr.val = visr.val | value; - } - - /* Set up ISR.r/w */ - visr.r = read; - visr.w = write; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr (vcpu,visr.val); -} - - - -/* - * Set up ISR for break fault - */ -void set_break_isr (VCPU *vcpu) -{ - ISR visr; - u64 value; - - /* Need set up ISR: ei, ni */ - - visr.val = 0; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr(vcpu, visr.val); -} - - - - - - -/* - * Set up ISR for Priviledged Operation fault - */ -void set_privileged_operation_isr (VCPU *vcpu,int inst) -{ - ISR visr; - u64 value; - - /* Need set up ISR: code, ei, ni, na */ - - visr.val = 0; - - /* Set up na, code{3:0} for no-access instruction */ - value = set_isr_for_na_inst (vcpu, inst); - visr.val = visr.val | value; - - - /* ISR.code{7:4} =1 */ - visr.code = (1 << 4) | visr.code; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr (vcpu, visr.val); -} - - - - -/* - * Set up ISR for Priviledged Register fault - */ -void set_privileged_reg_isr (VCPU *vcpu, int inst) -{ - ISR visr; - u64 value; - - /* Need set up ISR: code, ei, ni */ - - visr.val = 0; - - /* ISR.code{7:4} =2 */ - visr.code = 2 << 4; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr (vcpu, visr.val); -} - - - - - -/* - * Set up ISR for Reserved Register/Field fault - */ -void set_rsv_reg_field_isr (VCPU *vcpu) -{ - ISR visr; - u64 value; - - /* Need set up ISR: code, ei, ni */ - - visr.val = 0; - - /* ISR.code{7:4} =4 */ - visr.code = (3 << 4) | visr.code; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr (vcpu, visr.val); -} - - - -/* - * Set up ISR for Illegal Operation fault - */ -void set_illegal_op_isr (VCPU *vcpu) -{ - ISR visr; - u64 value; - - /* Need set up ISR: ei, ni */ - - visr.val = 0; - - /* Set up ei/ni */ - value = set_isr_ei_ni (vcpu); - visr.val = visr.val | value; - - vmx_vcpu_set_isr (vcpu, visr.val); -} - - -void set_isr_reg_nat_consumption(VCPU *vcpu, u64 flag, u64 non_access) -{ - ISR isr; - - isr.val = 0; - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_REG_NAT_CONSUMPTION_FAULT | flag; - isr.na = non_access; - isr.r = 1; - isr.w = 0; - vmx_vcpu_set_isr(vcpu, isr.val); - return; -} - -void set_isr_for_priv_fault(VCPU *vcpu, u64 non_access) -{ - u64 value; - ISR isr; - - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_PRIV_OP_FAULT; - isr.na = non_access; - vmx_vcpu_set_isr(vcpu, isr.val); - - return; -} - - -IA64FAULT check_target_register(VCPU *vcpu, u64 reg_index) -{ - u64 sof; - REGS *regs; - regs=vcpu_regs(vcpu); - sof = regs->cr_ifs & 0x7f; - if(reg_index >= sof + 32) - return IA64_FAULT; - return IA64_NO_FAULT;; -} - - -int is_reserved_rr_register(VCPU* vcpu, int reg_index) -{ - return (reg_index >= 8); -} - -#define ITIR_RSV_MASK (0x3UL | (((1UL<<32)-1) << 32)) -int is_reserved_itir_field(VCPU* vcpu, u64 itir) -{ - if ( itir & ITIR_RSV_MASK ) { - return 1; - } - return 0; -} - -int is_reserved_rr_field(VCPU* vcpu, u64 reg_value) -{ - ia64_rr rr; - rr.rrval = reg_value; - - if(rr.reserved0 != 0 || rr.reserved1 != 0){ - return 1; - } - if(rr.ps < 12 || rr.ps > 28){ - // page too big or small. - return 1; - } - if(rr.ps > 15 && rr.ps % 2 != 0){ - // unsupported page size. - return 1; - } - return 0; -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_vcpu.c --- a/xen/arch/ia64/vmx_vcpu.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,446 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_vcpu.c: handling all virtual cpu related thing. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Fred yang (fred.yang@xxxxxxxxx) - * Arun Sharma (arun.sharma@xxxxxxxxx) - * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <xen/sched.h> -#include <public/arch-ia64.h> -#include <asm/ia64_int.h> -#include <asm/vmx_vcpu.h> -#include <asm/regionreg.h> -#include <asm/tlb.h> -#include <asm/processor.h> -#include <asm/delay.h> -#include <asm/regs.h> -#include <asm/gcc_intrin.h> -#include <asm/vmx_mm_def.h> -#include <asm/vmx.h> - -//u64 fire_itc; -//u64 fire_itc2; -//u64 fire_itm; -//u64 fire_itm2; -/* - * Copyright (c) 2005 Intel Corporation. - * Anthony Xu (anthony.xu@xxxxxxxxx) - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - * - * 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. - * - */ - -/************************************************************************** - VCPU general register access routines -**************************************************************************/ -#include <asm/hw_irq.h> -#include <asm/vmx_pal_vsa.h> -#include <asm/kregs.h> - -//unsigned long last_guest_rsm = 0x0; -struct guest_psr_bundle{ - unsigned long ip; - unsigned long psr; -}; - -struct guest_psr_bundle guest_psr_buf[100]; -unsigned long guest_psr_index = 0; - -void -vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value) -{ - - UINT64 mask; - REGS *regs; - IA64_PSR old_psr, new_psr; - old_psr.val=vmx_vcpu_get_psr(vcpu); - - regs=vcpu_regs(vcpu); - /* We only support guest as: - * vpsr.pk = 0 - * vpsr.is = 0 - * Otherwise panic - */ - if ( value & (IA64_PSR_PK | IA64_PSR_IS | IA64_PSR_VM )) { - panic ("Setting unsupport guest psr!"); - } - - /* - * For those IA64_PSR bits: id/da/dd/ss/ed/ia - * Since these bits will become 0, after success execution of each - * instruction, we will change set them to mIA64_PSR - */ - VMX_VPD(vcpu,vpsr) = value & - (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | - IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA - )); - - if ( !old_psr.i && (value & IA64_PSR_I) ) { - // vpsr.i 0->1 - vcpu->arch.irq_new_condition = 1; - } - new_psr.val=vmx_vcpu_get_psr(vcpu); - { - struct pt_regs *regs = vcpu_regs(vcpu); - guest_psr_buf[guest_psr_index].ip = regs->cr_iip; - guest_psr_buf[guest_psr_index].psr = new_psr.val; - if (++guest_psr_index >= 100) - guest_psr_index = 0; - } -#if 0 - if (old_psr.i != new_psr.i) { - if (old_psr.i) - last_guest_rsm = vcpu_regs(vcpu)->cr_iip; - else - last_guest_rsm = 0; - } -#endif - - /* - * All vIA64_PSR bits shall go to mPSR (v->tf->tf_special.psr) - * , except for the following bits: - * ic/i/dt/si/rt/mc/it/bn/vm - */ - mask = IA64_PSR_IC + IA64_PSR_I + IA64_PSR_DT + IA64_PSR_SI + - IA64_PSR_RT + IA64_PSR_MC + IA64_PSR_IT + IA64_PSR_BN + - IA64_PSR_VM; - - regs->cr_ipsr = (regs->cr_ipsr & mask ) | ( value & (~mask) ); - - check_mm_mode_switch(vcpu, old_psr, new_psr); - return IA64_NO_FAULT; -} - -/* Adjust slot both in pt_regs and vpd, upon vpsr.ri which - * should have sync with ipsr in entry. - * - * Clear some bits due to successfully emulation. - */ -IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu) -{ - // TODO: trap_bounce?? Eddie - REGS *regs = vcpu_regs(vcpu); - IA64_PSR vpsr; - IA64_PSR *ipsr = (IA64_PSR *)®s->cr_ipsr; - - vpsr.val = vmx_vcpu_get_psr(vcpu); - if (vpsr.ri == 2) { - vpsr.ri = 0; - regs->cr_iip += 16; - } else { - vpsr.ri++; - } - - ipsr->ri = vpsr.ri; - vpsr.val &= - (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | - IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA - )); - - VMX_VPD(vcpu, vpsr) = vpsr.val; - - ipsr->val &= - (~ (IA64_PSR_ID |IA64_PSR_DA | IA64_PSR_DD | - IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA - )); - - return (IA64_NO_FAULT); -} - - -IA64FAULT vmx_vcpu_cover(VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - IA64_PSR vpsr; - vpsr.val = vmx_vcpu_get_psr(vcpu); - - if(!vpsr.ic) - VPD_CR(vcpu,ifs) = regs->cr_ifs; - regs->cr_ifs = IA64_IFS_V; - return (IA64_NO_FAULT); -} - - -thash_cb_t * -vmx_vcpu_get_vtlb(VCPU *vcpu) -{ - return vcpu->arch.vtlb; -} - - -struct virutal_platform_def * -vmx_vcpu_get_plat(VCPU *vcpu) -{ - return &(vcpu->domain->arch.vmx_platform); -} - - -ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr) -{ - return (ia64_rr)VMX(vcpu,vrr[vadr>>61]); -} - - -IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) -{ - ia64_rr oldrr,newrr; - thash_cb_t *hcb; - oldrr=vmx_vcpu_rr(vcpu,reg); - newrr.rrval=val; -#if 1 - if(oldrr.ps!=newrr.ps){ - hcb = vmx_vcpu_get_vtlb(vcpu); - thash_purge_all(hcb); - } -#endif - VMX(vcpu,vrr[reg>>61]) = val; - switch((u64)(reg>>61)) { - case VRN5: - VMX(vcpu,mrr5)=vmx_vrrtomrr(vcpu,val); - break; - case VRN6: - VMX(vcpu,mrr6)=vmx_vrrtomrr(vcpu,val); - break; - case VRN7: - VMX(vcpu,mrr7)=vmx_vrrtomrr(vcpu,val); - /* Change double mapping for this domain */ -#ifdef XEN_DBL_MAPPING - vmx_change_double_mapping(vcpu, - vmx_vrrtomrr(vcpu,oldrr.rrval), - vmx_vrrtomrr(vcpu,newrr.rrval)); -#endif - break; - default: - ia64_set_rr(reg,vmx_vrrtomrr(vcpu,val)); - break; - } - - return (IA64_NO_FAULT); -} - - - -/************************************************************************** - VCPU protection key register access routines -**************************************************************************/ - -IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval) -{ - UINT64 val = (UINT64)ia64_get_pkr(reg); - *pval = val; - return (IA64_NO_FAULT); -} - -IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val) -{ - ia64_set_pkr(reg,val); - return (IA64_NO_FAULT); -} - -#if 0 -int tlb_debug=0; -check_entry(u64 va, u64 ps, char *str) -{ - va &= ~ (PSIZE(ps)-1); - if ( va == 0x2000000002908000UL || - va == 0x600000000000C000UL ) { - stop(); - } - if (tlb_debug) printf("%s at %lx %lx\n", str, va, 1UL<<ps); -} -#endif - - -u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa) -{ - ia64_rr rr,rr1; - rr=vmx_vcpu_rr(vcpu,ifa); - rr1.rrval=0; - rr1.ps=rr.ps; - rr1.rid=rr.rid; - return (rr1.rrval); -} - - - - -IA64FAULT vmx_vcpu_rfi(VCPU *vcpu) -{ - // TODO: Only allowed for current vcpu - UINT64 ifs, psr; - REGS *regs = vcpu_regs(vcpu); - psr = VPD_CR(vcpu,ipsr); - vmx_vcpu_set_psr(vcpu,psr); - ifs=VPD_CR(vcpu,ifs); - if((ifs>>63)&&(ifs<<1)){ - ifs=(regs->cr_ifs)&0x7f; - regs->rfi_pfs = (ifs<<7)|ifs; - regs->cr_ifs = VPD_CR(vcpu,ifs); - } - regs->cr_iip = VPD_CR(vcpu,iip); - return (IA64_NO_FAULT); -} - - -UINT64 -vmx_vcpu_get_psr(VCPU *vcpu) -{ - return VMX_VPD(vcpu,vpsr); -} - - -IA64FAULT -vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val) -{ - IA64_PSR vpsr; - - vpsr.val = vmx_vcpu_get_psr(vcpu); - if ( vpsr.bn ) { - *val=VMX_VPD(vcpu,vgr[reg-16]); - // Check NAT bit - if ( VMX_VPD(vcpu,vnat) & (1UL<<(reg-16)) ) { - // TODO - //panic ("NAT consumption fault\n"); - return IA64_FAULT; - } - - } - else { - *val=VMX_VPD(vcpu,vbgr[reg-16]); - if ( VMX_VPD(vcpu,vbnat) & (1UL<<reg) ) { - //panic ("NAT consumption fault\n"); - return IA64_FAULT; - } - - } - return IA64_NO_FAULT; -} - -IA64FAULT -vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat) -{ - IA64_PSR vpsr; - vpsr.val = vmx_vcpu_get_psr(vcpu); - if ( vpsr.bn ) { - VMX_VPD(vcpu,vgr[reg-16]) = val; - if(nat){ - VMX_VPD(vcpu,vnat) |= ( 1UL<<(reg-16) ); - }else{ - VMX_VPD(vcpu,vbnat) &= ~( 1UL<<(reg-16) ); - } - } - else { - VMX_VPD(vcpu,vbgr[reg-16]) = val; - if(nat){ - VMX_VPD(vcpu,vnat) |= ( 1UL<<(reg) ); - }else{ - VMX_VPD(vcpu,vbnat) &= ~( 1UL<<(reg) ); - } - } - return IA64_NO_FAULT; -} - - - -IA64FAULT -vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val) -{ - REGS *regs=vcpu_regs(vcpu); - int nat; - //TODO, Eddie - if (!regs) return 0; - if (reg >= 16 && reg < 32) { - return vmx_vcpu_get_bgr(vcpu,reg,val); - } - getreg(reg,val,&nat,regs); // FIXME: handle NATs later - if(nat){ - return IA64_FAULT; - } - return IA64_NO_FAULT; -} - -// returns: -// IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault -// IA64_NO_FAULT otherwise - -IA64FAULT -vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat) -{ - REGS *regs = vcpu_regs(vcpu); - long sof = (regs->cr_ifs) & 0x7f; - //TODO Eddie - - if (!regs) return IA64_ILLOP_FAULT; - if (reg >= sof + 32) return IA64_ILLOP_FAULT; - if ( reg >= 16 && reg < 32 ) { - return vmx_vcpu_set_bgr(vcpu,reg, value, nat); - } - setreg(reg,value,nat,regs); - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) -{ - UINT64 vpsr; - vpsr = vmx_vcpu_get_psr(vcpu); - vpsr &= (~imm24); - vmx_vcpu_set_psr(vcpu, vpsr); - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) -{ - UINT64 vpsr; - vpsr = vmx_vcpu_get_psr(vcpu); - vpsr |= imm24; - vmx_vcpu_set_psr(vcpu, vpsr); - return IA64_NO_FAULT; -} - - -IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val) -{ - vmx_vcpu_set_psr(vcpu, val); - return IA64_NO_FAULT; -} - -IA64FAULT -vmx_vcpu_set_tpr(VCPU *vcpu, u64 val) -{ - VPD_CR(vcpu,tpr)=val; - vcpu->arch.irq_new_condition = 1; - return IA64_NO_FAULT; -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_virt.c --- a/xen/arch/ia64/vmx_virt.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1511 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_virt.c: - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Fred yang (fred.yang@xxxxxxxxx) - * Shaofan Li (Susue Li) <susie.li@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - - - -#include <asm/privop.h> -#include <asm/vmx_vcpu.h> -#include <asm/processor.h> -#include <asm/delay.h> // Debug only -#include <asm/vmmu.h> -#include <asm/vmx_mm_def.h> -#include <asm/smp.h> - -#include <asm/virt_event.h> -extern UINT64 privop_trace; - -void -ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause) -{ - *cause=0; - switch (slot_type) { - case M: - if (inst.generic.major==0){ - if(inst.M28.x3==0){ - if(inst.M44.x4==6){ - *cause=EVENT_SSM; - }else if(inst.M44.x4==7){ - *cause=EVENT_RSM; - }else if(inst.M30.x4==8&&inst.M30.x2==2){ - *cause=EVENT_MOV_TO_AR_IMM; - } - } - } - else if(inst.generic.major==1){ - if(inst.M28.x3==0){ - if(inst.M32.x6==0x2c){ - *cause=EVENT_MOV_TO_CR; - }else if(inst.M33.x6==0x24){ - *cause=EVENT_MOV_FROM_CR; - }else if(inst.M35.x6==0x2d){ - *cause=EVENT_MOV_TO_PSR; - }else if(inst.M36.x6==0x25){ - *cause=EVENT_MOV_FROM_PSR; - }else if(inst.M29.x6==0x2A){ - *cause=EVENT_MOV_TO_AR; - }else if(inst.M31.x6==0x22){ - *cause=EVENT_MOV_FROM_AR; - }else if(inst.M45.x6==0x09){ - *cause=EVENT_PTC_L; - }else if(inst.M45.x6==0x0A){ - *cause=EVENT_PTC_G; - }else if(inst.M45.x6==0x0B){ - *cause=EVENT_PTC_GA; - }else if(inst.M45.x6==0x0C){ - *cause=EVENT_PTR_D; - }else if(inst.M45.x6==0x0D){ - *cause=EVENT_PTR_I; - }else if(inst.M46.x6==0x1A){ - *cause=EVENT_THASH; - }else if(inst.M46.x6==0x1B){ - *cause=EVENT_TTAG; - }else if(inst.M46.x6==0x1E){ - *cause=EVENT_TPA; - }else if(inst.M46.x6==0x1F){ - *cause=EVENT_TAK; - }else if(inst.M47.x6==0x34){ - *cause=EVENT_PTC_E; - }else if(inst.M41.x6==0x2E){ - *cause=EVENT_ITC_D; - }else if(inst.M41.x6==0x2F){ - *cause=EVENT_ITC_I; - }else if(inst.M42.x6==0x00){ - *cause=EVENT_MOV_TO_RR; - }else if(inst.M42.x6==0x01){ - *cause=EVENT_MOV_TO_DBR; - }else if(inst.M42.x6==0x02){ - *cause=EVENT_MOV_TO_IBR; - }else if(inst.M42.x6==0x03){ - *cause=EVENT_MOV_TO_PKR; - }else if(inst.M42.x6==0x04){ - *cause=EVENT_MOV_TO_PMC; - }else if(inst.M42.x6==0x05){ - *cause=EVENT_MOV_TO_PMD; - }else if(inst.M42.x6==0x0E){ - *cause=EVENT_ITR_D; - }else if(inst.M42.x6==0x0F){ - *cause=EVENT_ITR_I; - }else if(inst.M43.x6==0x10){ - *cause=EVENT_MOV_FROM_RR; - }else if(inst.M43.x6==0x11){ - *cause=EVENT_MOV_FROM_DBR; - }else if(inst.M43.x6==0x12){ - *cause=EVENT_MOV_FROM_IBR; - }else if(inst.M43.x6==0x13){ - *cause=EVENT_MOV_FROM_PKR; - }else if(inst.M43.x6==0x14){ - *cause=EVENT_MOV_FROM_PMC; -/* - }else if(inst.M43.x6==0x15){ - *cause=EVENT_MOV_FROM_PMD; -*/ - }else if(inst.M43.x6==0x17){ - *cause=EVENT_MOV_FROM_CPUID; - } - } - } - break; - case B: - if(inst.generic.major==0){ - if(inst.B8.x6==0x02){ - *cause=EVENT_COVER; - }else if(inst.B8.x6==0x08){ - *cause=EVENT_RFI; - }else if(inst.B8.x6==0x0c){ - *cause=EVENT_BSW_0; - }else if(inst.B8.x6==0x0d){ - *cause=EVENT_BSW_1; - } - } - } -} - -IA64FAULT vmx_emul_rsm(VCPU *vcpu, INST64 inst) -{ - UINT64 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; - return vmx_vcpu_set_psr_sm(vcpu,imm24); -} - -unsigned long last_guest_psr = 0x0; -IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst) -{ - UINT64 tgt = inst.M33.r1; - UINT64 val; - IA64FAULT fault; - -/* - if ((fault = vmx_vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) - return vmx_vcpu_set_gr(vcpu, tgt, val); - else return fault; - */ - val = vmx_vcpu_get_psr(vcpu); - val = (val & MASK(0, 32)) | (val & MASK(35, 2)); - last_guest_psr = val; - return vmx_vcpu_set_gr(vcpu, tgt, val, 0); -} - -/** - * @todo Check for reserved bits and return IA64_RSVDREG_FAULT. - */ -IA64FAULT vmx_emul_mov_to_psr(VCPU *vcpu, INST64 inst) -{ - UINT64 val; - IA64FAULT fault; - if(vmx_vcpu_get_gr(vcpu, inst.M35.r2, &val) != IA64_NO_FAULT) - panic(" get_psr nat bit fault\n"); - - val = (val & MASK(0, 32)) | (VMX_VPD(vcpu, vpsr) & MASK(32, 32)); -#if 0 - if (last_mov_from_psr && (last_guest_psr != (val & MASK(0,32)))) - while(1); - else - last_mov_from_psr = 0; -#endif - return vmx_vcpu_set_psr_l(vcpu,val); -} - - -/************************************************************************** -Privileged operation emulation routines -**************************************************************************/ - -IA64FAULT vmx_emul_rfi(VCPU *vcpu, INST64 inst) -{ - IA64_PSR vpsr; - REGS *regs; -#ifdef CHECK_FAULT - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - regs=vcpu_regs(vcpu); - vpsr.val=regs->cr_ipsr; - if ( vpsr.is == 1 ) { - panic ("We do not support IA32 instruction yet"); - } - - return vmx_vcpu_rfi(vcpu); -} - -IA64FAULT vmx_emul_bsw0(VCPU *vcpu, INST64 inst) -{ -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - return vmx_vcpu_bsw0(vcpu); -} - -IA64FAULT vmx_emul_bsw1(VCPU *vcpu, INST64 inst) -{ -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - return vmx_vcpu_bsw1(vcpu); -} - -IA64FAULT vmx_emul_cover(VCPU *vcpu, INST64 inst) -{ - return vmx_vcpu_cover(vcpu); -} - -IA64FAULT vmx_emul_ptc_l(VCPU *vcpu, INST64 inst) -{ - u64 r2,r3; - ISR isr; - IA64_PSR vpsr; - - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&r2)){ -#ifdef VMAL_NO_FAULT_CHECK - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif // VMAL_NO_FAULT_CHECK - } -#ifdef VMAL_NO_FAULT_CHECK - if (unimplemented_gva(vcpu,r3) ) { - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - return vmx_vcpu_ptc_l(vcpu,r3,bits(r2,2,7)); -} - -IA64FAULT vmx_emul_ptc_e(VCPU *vcpu, INST64 inst) -{ - u64 r3; - ISR isr; - IA64_PSR vpsr; - - vpsr.val=vmx_vcpu_get_psr(vcpu); -#ifdef VMAL_NO_FAULT_CHECK - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - if(vmx_vcpu_get_gr(vcpu,inst.M47.r3,&r3)){ -#ifdef VMAL_NO_FAULT_CHECK - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif // VMAL_NO_FAULT_CHECK - } - return vmx_vcpu_ptc_e(vcpu,r3); -} - -IA64FAULT vmx_emul_ptc_g(VCPU *vcpu, INST64 inst) -{ - return vmx_emul_ptc_l(vcpu, inst); -} - -IA64FAULT vmx_emul_ptc_ga(VCPU *vcpu, INST64 inst) -{ - return vmx_emul_ptc_l(vcpu, inst); -} - -IA64FAULT ptr_fault_check(VCPU *vcpu, INST64 inst, u64 *pr2, u64 *pr3) -{ - ISR isr; - IA64FAULT ret1, ret2; - -#ifdef VMAL_NO_FAULT_CHECK - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - ret1 = vmx_vcpu_get_gr(vcpu,inst.M45.r3,pr3); - ret2 = vmx_vcpu_get_gr(vcpu,inst.M45.r2,pr2); -#ifdef VMAL_NO_FAULT_CHECK - if ( ret1 != IA64_NO_FAULT || ret2 != IA64_NO_FAULT ) { - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; - } - if (unimplemented_gva(vcpu,r3) ) { - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - return IA64_NO_FAULT; -} - -IA64FAULT vmx_emul_ptr_d(VCPU *vcpu, INST64 inst) -{ - u64 r2,r3; - if ( ptr_fault_check(vcpu, inst, &r2, &r3 ) == IA64_FAULT ) - return IA64_FAULT; - return vmx_vcpu_ptr_d(vcpu,r3,bits(r2,2,7)); -} - -IA64FAULT vmx_emul_ptr_i(VCPU *vcpu, INST64 inst) -{ - u64 r2,r3; - if ( ptr_fault_check(vcpu, inst, &r2, &r3 ) == IA64_FAULT ) - return IA64_FAULT; - return vmx_vcpu_ptr_i(vcpu,r3,bits(r2,2,7)); -} - - -IA64FAULT vmx_emul_thash(VCPU *vcpu, INST64 inst) -{ - u64 r1,r3; - ISR visr; - IA64_PSR vpsr; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M46.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ -#ifdef CHECK_FAULT - vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); - return IA64_NO_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(unimplemented_gva(vcpu, r3)){ - vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); - return IA64_NO_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_thash(vcpu, r3, &r1); - vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); - return(IA64_NO_FAULT); -} - - -IA64FAULT vmx_emul_ttag(VCPU *vcpu, INST64 inst) -{ - u64 r1,r3; - ISR visr; - IA64_PSR vpsr; - #ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M46.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ -#ifdef CHECK_FAULT - vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); - return IA64_NO_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(unimplemented_gva(vcpu, r3)){ - vmx_vcpu_set_gr(vcpu, inst.M46.r1, 0, 1); - return IA64_NO_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_ttag(vcpu, r3, &r1); - vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); - return(IA64_NO_FAULT); -} - - -IA64FAULT vmx_emul_tpa(VCPU *vcpu, INST64 inst) -{ - u64 r1,r3; - ISR visr; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M46.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if(vpsr.cpl!=0){ - visr.val=0; - vcpu_set_isr(vcpu, visr.val); - return IA64_FAULT; - } -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,1); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if (unimplemented_gva(vcpu,r3) ) { - // inject unimplemented_data_address_fault - visr.val = set_isr_ei_ni(vcpu); - visr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - // FAULT_UNIMPLEMENTED_DATA_ADDRESS. - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - - if(vmx_vcpu_tpa(vcpu, r3, &r1)){ - return IA64_FAULT; - } - vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); - return(IA64_NO_FAULT); -} - -IA64FAULT vmx_emul_tak(VCPU *vcpu, INST64 inst) -{ - u64 r1,r3; - ISR visr; - IA64_PSR vpsr; - int fault=IA64_NO_FAULT; -#ifdef CHECK_FAULT - visr.val=0; - if(check_target_register(vcpu, inst.M46.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - vpsr.val=vmx_vcpu_get_psr(vcpu); - if(vpsr.cpl!=0){ - vcpu_set_isr(vcpu, visr.val); - return IA64_FAULT; - } -#endif - if(vmx_vcpu_get_gr(vcpu, inst.M46.r3, &r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,1); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif - } - if(vmx_vcpu_tak(vcpu, r3, &r1)){ - return IA64_FAULT; - } - vmx_vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); - return(IA64_NO_FAULT); -} - - -/************************************ - * Insert translation register/cache -************************************/ - -IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst) -{ - UINT64 fault, itir, ifa, pte, slot; - ISR isr; - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.ic ) { - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#ifdef VMAL_NO_FAULT_CHECK - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&slot)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&pte)){ -#ifdef VMAL_NO_FAULT_CHECK - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif // VMAL_NO_FAULT_CHECK - } -#ifdef VMAL_NO_FAULT_CHECK - if(is_reserved_rr_register(vcpu, slot)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - - if (vmx_vcpu_get_itir(vcpu,&itir)){ - return(IA64_FAULT); - } - if (vmx_vcpu_get_ifa(vcpu,&ifa)){ - return(IA64_FAULT); - } -#ifdef VMAL_NO_FAULT_CHECK - if (is_reserved_itir_field(vcpu, itir)) { - // TODO - return IA64_FAULT; - } - if (unimplemented_gva(vcpu,ifa) ) { - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - - return (vmx_vcpu_itr_d(vcpu,pte,itir,ifa,slot)); -} - -IA64FAULT vmx_emul_itr_i(VCPU *vcpu, INST64 inst) -{ - UINT64 fault, itir, ifa, pte, slot; - ISR isr; - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.ic ) { - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#ifdef VMAL_NO_FAULT_CHECK - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - if(vmx_vcpu_get_gr(vcpu,inst.M45.r3,&slot)||vmx_vcpu_get_gr(vcpu,inst.M45.r2,&pte)){ -#ifdef VMAL_NO_FAULT_CHECK - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif // VMAL_NO_FAULT_CHECK - } -#ifdef VMAL_NO_FAULT_CHECK - if(is_reserved_rr_register(vcpu, slot)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - - if (vmx_vcpu_get_itir(vcpu,&itir)){ - return(IA64_FAULT); - } - if (vmx_vcpu_get_ifa(vcpu,&ifa)){ - return(IA64_FAULT); - } -#ifdef VMAL_NO_FAULT_CHECK - if (is_reserved_itir_field(vcpu, itir)) { - // TODO - return IA64_FAULT; - } - if (unimplemented_gva(vcpu,ifa) ) { - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - - return (vmx_vcpu_itr_i(vcpu,pte,itir,ifa,slot)); -} - -IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte) -{ - UINT64 fault; - ISR isr; - IA64_PSR vpsr; - IA64FAULT ret1; - - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.ic ) { - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - -#ifdef VMAL_NO_FAULT_CHECK - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - ret1 = vmx_vcpu_get_gr(vcpu,inst.M45.r2,pte); -#ifdef VMAL_NO_FAULT_CHECK - if( ret1 != IA64_NO_FAULT ){ - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - - if (vmx_vcpu_get_itir(vcpu,itir)){ - return(IA64_FAULT); - } - if (vmx_vcpu_get_ifa(vcpu,ifa)){ - return(IA64_FAULT); - } -#ifdef VMAL_NO_FAULT_CHECK - if (unimplemented_gva(vcpu,ifa) ) { - isr.val = set_isr_ei_ni(vcpu); - isr.code = IA64_RESERVED_REG_FAULT; - vcpu_set_isr(vcpu, isr.val); - unimpl_daddr(vcpu); - return IA64_FAULT; - } -#endif // VMAL_NO_FAULT_CHECK - return IA64_NO_FAULT; -} - -IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst) -{ - UINT64 itir, ifa, pte; - - if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { - return IA64_FAULT; - } - - return (vmx_vcpu_itc_d(vcpu,pte,itir,ifa)); -} - -IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst) -{ - UINT64 itir, ifa, pte; - - if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { - return IA64_FAULT; - } - - return (vmx_vcpu_itc_i(vcpu,pte,itir,ifa)); - -} - -/************************************* - * Moves to semi-privileged registers -*************************************/ - -IA64FAULT vmx_emul_mov_to_ar_imm(VCPU *vcpu, INST64 inst) -{ - // I27 and M30 are identical for these fields - if(inst.M30.ar3!=44){ - panic("Can't support ar register other than itc"); - } -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - UINT64 imm; - if(inst.M30.s){ - imm = -inst.M30.imm; - }else{ - imm = inst.M30.imm; - } - return (vmx_vcpu_set_itc(vcpu, imm)); -} - -IA64FAULT vmx_emul_mov_to_ar_reg(VCPU *vcpu, INST64 inst) -{ - // I26 and M29 are identical for these fields - u64 r2; - if(inst.M29.ar3!=44){ - panic("Can't support ar register other than itc"); - } - if(vmx_vcpu_get_gr(vcpu,inst.M29.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - return (vmx_vcpu_set_itc(vcpu, r2)); -} - - -IA64FAULT vmx_emul_mov_from_ar_reg(VCPU *vcpu, INST64 inst) -{ - // I27 and M30 are identical for these fields - if(inst.M31.ar3!=44){ - panic("Can't support ar register other than itc"); - } -#ifdef CHECK_FAULT - if(check_target_register(vcpu,inst.M31.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.si&& vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - u64 r1; - vmx_vcpu_get_itc(vcpu,&r1); - vmx_vcpu_set_gr(vcpu,inst.M31.r1,r1,0); - return IA64_NO_FAULT; -} - - -/******************************** - * Moves to privileged registers -********************************/ - -IA64FAULT vmx_emul_mov_to_pkr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_pkr(vcpu,r3,r2)); -} - -IA64FAULT vmx_emul_mov_to_rr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_rr(vcpu,r3,r2)); -} - -IA64FAULT vmx_emul_mov_to_dbr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_dbr(vcpu,r3,r2)); -} - -IA64FAULT vmx_emul_mov_to_ibr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_ibr(vcpu,r3,r2)); -} - -IA64FAULT vmx_emul_mov_to_pmc(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_pmc(vcpu,r3,r2)); -} - -IA64FAULT vmx_emul_mov_to_pmd(VCPU *vcpu, INST64 inst) -{ - u64 r3,r2; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M42.r3,&r3)||vmx_vcpu_get_gr(vcpu,inst.M42.r2,&r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } - return (vmx_vcpu_set_pmd(vcpu,r3,r2)); -} - - -/********************************** - * Moves from privileged registers - **********************************/ - -IA64FAULT vmx_emul_mov_from_rr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_rr_register(vcpu,r3>>VRN_SHIFT)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - } -#endif //CHECK_FAULT - vmx_vcpu_get_rr(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_from_pkr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_indirect_register(vcpu,r3)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_get_pkr(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_from_dbr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_indirect_register(vcpu,r3)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_get_dbr(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_from_ibr(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_indirect_register(vcpu,r3)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_get_ibr(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_from_pmc(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if (vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } - -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_indirect_register(vcpu,r3)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_get_pmc(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_from_cpuid(VCPU *vcpu, INST64 inst) -{ - u64 r3,r1; -#ifdef CHECK_FAULT - if(check_target_register(vcpu, inst.M43.r1)){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu,inst.M43.r3,&r3)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if(is_reserved_indirect_register(vcpu,r3)){ - set_rsv_reg_field_isr(vcpu); - rsv_reg_field(vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - vmx_vcpu_get_cpuid(vcpu,r3,&r1); - return vmx_vcpu_set_gr(vcpu, inst.M43.r1, r1,0); -} - -IA64FAULT vmx_emul_mov_to_cr(VCPU *vcpu, INST64 inst) -{ - u64 r2,cr3; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if(is_reserved_cr(inst.M32.cr3)||(vpsr.ic&&is_interruption_control_cr(inst.M32.cr3))){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - if(vmx_vcpu_get_gr(vcpu, inst.M32.r2, &r2)){ -#ifdef CHECK_FAULT - set_isr_reg_nat_consumption(vcpu,0,0); - rnat_comsumption(vcpu); - return IA64_FAULT; -#endif //CHECK_FAULT - } -#ifdef CHECK_FAULT - if ( check_cr_rsv_fields (inst.M32.cr3, r2)) { - /* Inject Reserved Register/Field fault - * into guest */ - set_rsv_reg_field_isr (vcpu,0); - rsv_reg_field (vcpu); - return IA64_FAULT; - } -#endif //CHECK_FAULT - extern u64 cr_igfld_mask(int index, u64 value); - r2 = cr_igfld_mask(inst.M32.cr3,r2); - VMX_VPD(vcpu, vcr[inst.M32.cr3]) = r2; - switch (inst.M32.cr3) { - case 0: return vmx_vcpu_set_dcr(vcpu,r2); - case 1: return vmx_vcpu_set_itm(vcpu,r2); - case 2: return vmx_vcpu_set_iva(vcpu,r2); - case 8: return vmx_vcpu_set_pta(vcpu,r2); - case 16:return vmx_vcpu_set_ipsr(vcpu,r2); - case 17:return vmx_vcpu_set_isr(vcpu,r2); - case 19:return vmx_vcpu_set_iip(vcpu,r2); - case 20:return vmx_vcpu_set_ifa(vcpu,r2); - case 21:return vmx_vcpu_set_itir(vcpu,r2); - case 22:return vmx_vcpu_set_iipa(vcpu,r2); - case 23:return vmx_vcpu_set_ifs(vcpu,r2); - case 24:return vmx_vcpu_set_iim(vcpu,r2); - case 25:return vmx_vcpu_set_iha(vcpu,r2); - case 64:printk("SET LID to 0x%lx\n", r2); - return vmx_vcpu_set_lid(vcpu,r2); - case 65:return IA64_NO_FAULT; - case 66:return vmx_vcpu_set_tpr(vcpu,r2); - case 67:return vmx_vcpu_set_eoi(vcpu,r2); - case 68:return IA64_NO_FAULT; - case 69:return IA64_NO_FAULT; - case 70:return IA64_NO_FAULT; - case 71:return IA64_NO_FAULT; - case 72:return vmx_vcpu_set_itv(vcpu,r2); - case 73:return vmx_vcpu_set_pmv(vcpu,r2); - case 74:return vmx_vcpu_set_cmcv(vcpu,r2); - case 80:return vmx_vcpu_set_lrr0(vcpu,r2); - case 81:return vmx_vcpu_set_lrr1(vcpu,r2); - default: return IA64_NO_FAULT; - } -} - - -#define cr_get(cr) \ - ((fault=vmx_vcpu_get_##cr(vcpu,&val))==IA64_NO_FAULT)?\ - vmx_vcpu_set_gr(vcpu, tgt, val,0):fault; - - -IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst) -{ - UINT64 tgt = inst.M33.r1; - UINT64 val; - IA64FAULT fault; -#ifdef CHECK_FAULT - IA64_PSR vpsr; - vpsr.val=vmx_vcpu_get_psr(vcpu); - if(is_reserved_cr(inst.M33.cr3)||is_read_only_cr(inst.M33.cr3|| - (vpsr.ic&&is_interruption_control_cr(inst.M33.cr3)))){ - set_illegal_op_isr(vcpu); - illegal_op(vcpu); - return IA64_FAULT; - } - if ( vpsr.cpl != 0) { - /* Inject Privileged Operation fault into guest */ - set_privileged_operation_isr (vcpu, 0); - privilege_op (vcpu); - return IA64_FAULT; - } -#endif // CHECK_FAULT - -// from_cr_cnt[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:val = ia64_getreg(_IA64_REG_CR_LID); -// return vmx_vcpu_set_gr(vcpu,tgt,val,0); - case 64:return cr_get(lid); - case 65: - vmx_vcpu_get_ivr(vcpu,&val); - return vmx_vcpu_set_gr(vcpu,tgt,val,0); - case 66:return cr_get(tpr); - case 67:return vmx_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: - panic("Read reserved cr register"); - } -} - - -static void post_emulation_action(VCPU *vcpu) -{ - if ( vcpu->arch.irq_new_condition ) { - vcpu->arch.irq_new_condition = 0; - vhpi_detection(vcpu); - } -} - -//#define BYPASS_VMAL_OPCODE -extern IA64_SLOT_TYPE slot_types[0x20][3]; -IA64_BUNDLE __vmx_get_domain_bundle(u64 iip) -{ - IA64_BUNDLE bundle; - - fetch_code( current,iip, &bundle.i64[0]); - fetch_code( current,iip+8, &bundle.i64[1]); - return bundle; -} - -/** Emulate a privileged operation. - * - * - * @param vcpu virtual cpu - * @cause the reason cause virtualization fault - * @opcode the instruction code which cause virtualization fault - */ - -void -vmx_emulate(VCPU *vcpu, UINT64 cause, UINT64 opcode) -{ - IA64_BUNDLE bundle; - int slot; - IA64_SLOT_TYPE slot_type; - IA64FAULT status; - INST64 inst; - REGS * regs; - UINT64 iip; - regs = vcpu_regs(vcpu); - iip = regs->cr_iip; - IA64_PSR vpsr; -/* - if (privop_trace) { - static long i = 400; - //if (i > 0) printf("privop @%p\n",iip); - if (i > 0) printf("priv_handle_op: @%p, itc=%lx, itm=%lx\n", - iip,ia64_get_itc(),ia64_get_itm()); - i--; - } -*/ -#ifdef VTLB_DEBUG - check_vtlb_sanity(vmx_vcpu_get_vtlb(vcpu)); - dump_vtlb(vmx_vcpu_get_vtlb(vcpu)); -#endif -#if 0 -if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { - printf ("VMAL decode error: cause - %lx; op - %lx\n", - cause, opcode ); - return; -} -#endif -#ifdef BYPASS_VMAL_OPCODE - // make a local copy of the bundle containing the privop - bundle = __vmx_get_domain_bundle(iip); - slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; - if (!slot) inst.inst = bundle.slot0; - else if (slot == 1) - inst.inst = bundle.slot1a + (bundle.slot1b<<18); - else if (slot == 2) inst.inst = bundle.slot2; - else printf("priv_handle_op: illegal slot: %d\n", slot); - slot_type = slot_types[bundle.template][slot]; - ia64_priv_decoder(slot_type, inst, &cause); - if(cause==0){ - printf("This instruction at 0x%lx slot %d can't be virtualized", iip, slot); - panic("123456\n"); - } -#else - inst.inst=opcode; -#endif /* BYPASS_VMAL_OPCODE */ - - /* - * Switch to actual virtual rid in rr0 and rr4, - * which is required by some tlb related instructions. - */ - prepare_if_physical_mode(vcpu); - - switch(cause) { - case EVENT_RSM: - status=vmx_emul_rsm(vcpu, inst); - break; - case EVENT_SSM: - status=vmx_emul_ssm(vcpu, inst); - break; - case EVENT_MOV_TO_PSR: - status=vmx_emul_mov_to_psr(vcpu, inst); - break; - case EVENT_MOV_FROM_PSR: - status=vmx_emul_mov_from_psr(vcpu, inst); - break; - case EVENT_MOV_FROM_CR: - status=vmx_emul_mov_from_cr(vcpu, inst); - break; - case EVENT_MOV_TO_CR: - status=vmx_emul_mov_to_cr(vcpu, inst); - break; - case EVENT_BSW_0: - status=vmx_emul_bsw0(vcpu, inst); - break; - case EVENT_BSW_1: - status=vmx_emul_bsw1(vcpu, inst); - break; - case EVENT_COVER: - status=vmx_emul_cover(vcpu, inst); - break; - case EVENT_RFI: - status=vmx_emul_rfi(vcpu, inst); - break; - case EVENT_ITR_D: - status=vmx_emul_itr_d(vcpu, inst); - break; - case EVENT_ITR_I: - status=vmx_emul_itr_i(vcpu, inst); - break; - case EVENT_PTR_D: - status=vmx_emul_ptr_d(vcpu, inst); - break; - case EVENT_PTR_I: - status=vmx_emul_ptr_i(vcpu, inst); - break; - case EVENT_ITC_D: - status=vmx_emul_itc_d(vcpu, inst); - break; - case EVENT_ITC_I: - status=vmx_emul_itc_i(vcpu, inst); - break; - case EVENT_PTC_L: - status=vmx_emul_ptc_l(vcpu, inst); - break; - case EVENT_PTC_G: - status=vmx_emul_ptc_g(vcpu, inst); - break; - case EVENT_PTC_GA: - status=vmx_emul_ptc_ga(vcpu, inst); - break; - case EVENT_PTC_E: - status=vmx_emul_ptc_e(vcpu, inst); - break; - case EVENT_MOV_TO_RR: - status=vmx_emul_mov_to_rr(vcpu, inst); - break; - case EVENT_MOV_FROM_RR: - status=vmx_emul_mov_from_rr(vcpu, inst); - break; - case EVENT_THASH: - status=vmx_emul_thash(vcpu, inst); - break; - case EVENT_TTAG: - status=vmx_emul_ttag(vcpu, inst); - break; - case EVENT_TPA: - status=vmx_emul_tpa(vcpu, inst); - break; - case EVENT_TAK: - status=vmx_emul_tak(vcpu, inst); - break; - case EVENT_MOV_TO_AR_IMM: - status=vmx_emul_mov_to_ar_imm(vcpu, inst); - break; - case EVENT_MOV_TO_AR: - status=vmx_emul_mov_to_ar_reg(vcpu, inst); - break; - case EVENT_MOV_FROM_AR: - status=vmx_emul_mov_from_ar_reg(vcpu, inst); - break; - case EVENT_MOV_TO_DBR: - status=vmx_emul_mov_to_dbr(vcpu, inst); - break; - case EVENT_MOV_TO_IBR: - status=vmx_emul_mov_to_ibr(vcpu, inst); - break; - case EVENT_MOV_TO_PMC: - status=vmx_emul_mov_to_pmc(vcpu, inst); - break; - case EVENT_MOV_TO_PMD: - status=vmx_emul_mov_to_pmd(vcpu, inst); - break; - case EVENT_MOV_TO_PKR: - status=vmx_emul_mov_to_pkr(vcpu, inst); - break; - case EVENT_MOV_FROM_DBR: - status=vmx_emul_mov_from_dbr(vcpu, inst); - break; - case EVENT_MOV_FROM_IBR: - status=vmx_emul_mov_from_ibr(vcpu, inst); - break; - case EVENT_MOV_FROM_PMC: - status=vmx_emul_mov_from_pmc(vcpu, inst); - break; - case EVENT_MOV_FROM_PKR: - status=vmx_emul_mov_from_pkr(vcpu, inst); - break; - case EVENT_MOV_FROM_CPUID: - status=vmx_emul_mov_from_cpuid(vcpu, inst); - break; - case EVENT_VMSW: - printf ("Unimplemented instruction %d\n", cause); - status=IA64_FAULT; - break; - default: - printf("unknown cause %d, iip: %lx, ipsr: %lx\n", cause,regs->cr_iip,regs->cr_ipsr); - while(1); - /* For unknown cause, let hardware to re-execute */ - status=IA64_RETRY; - break; -// panic("unknown cause in virtualization intercept"); - }; - -#if 0 - if (status == IA64_FAULT) - panic("Emulation failed with cause %d:\n", cause); -#endif - - if ( status == IA64_NO_FAULT && cause !=EVENT_RFI ) { - vmx_vcpu_increment_iip(vcpu); - } - - recover_if_physical_mode(vcpu); - post_emulation_action (vcpu); -//TODO set_irq_check(v); - return; - -} - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vmx_vsa.S --- a/xen/arch/ia64/vmx_vsa.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,84 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_vsa.c: Call PAL virtualization services. - * Copyright (c) 2005, Intel Corporation. - * - * 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. - * - * Arun Sharma <arun.sharma@xxxxxxxxx> - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include <asm/asmmacro.h> - - - .text - -/* - * extern UINT64 ia64_call_vsa(UINT64 proc,UINT64 arg1, UINT64 arg2, - * UINT64 arg3, UINT64 arg4, UINT64 arg5, - * UINT64 arg6, UINT64 arg7); - * - * XXX: The currently defined services use only 4 args at the max. The - * rest are not consumed. - */ -GLOBAL_ENTRY(ia64_call_vsa) - .regstk 4,4,0,0 - -rpsave = loc0 -pfssave = loc1 -psrsave = loc2 -entry = loc3 -hostret = r24 - - alloc pfssave=ar.pfs,4,4,0,0 - mov rpsave=rp - movl entry=@gprel(__vsa_base) -1: mov hostret=ip - mov r25=in1 // copy arguments - mov r26=in2 - mov r27=in3 - mov psrsave=psr - ;; - add entry=entry,gp - tbit.nz p6,p0=psrsave,14 // IA64_PSR_I - tbit.nz p7,p0=psrsave,13 // IA64_PSR_IC - ;; - ld8 entry=[entry] // read entry point - ;; - add hostret=2f-1b,hostret // calculate return address - add entry=entry,in0 - ;; - rsm psr.i | psr.ic - ;; - srlz.d - mov b6=entry - br.cond.sptk b6 // call the service -2: - // Architectural sequence for enabling interrupts if necessary -(p7) ssm psr.ic - ;; -(p7) srlz.d - ;; -(p6) ssm psr.i - ;; - mov rp=rpsave - mov ar.pfs=pfssave - mov r8=r31 - ;; - srlz.d - br.ret.sptk rp - -END(ia64_call_vsa) - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/vtlb.c --- a/xen/arch/ia64/vtlb.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,1094 +0,0 @@ - -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vtlb.c: guest virtual tlb handling module. - * Copyright (c) 2004, Intel Corporation. - * - * 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. - * - * Yaozu Dong (Eddie Dong) (Eddie.dong@xxxxxxxxx) - * XiaoYan Feng (Fleming Feng) (Fleming.feng@xxxxxxxxx) - */ - -#include <linux/sched.h> -#include <asm/tlb.h> -#include <asm/mm.h> -#include <asm/vmx_mm_def.h> -#include <asm/gcc_intrin.h> -#include <linux/interrupt.h> -#include <asm/vmx_vcpu.h> -#define MAX_CCH_LENGTH 40 - - -static void cch_mem_init(thash_cb_t *hcb) -{ - thash_cch_mem_t *p, *q; - - hcb->cch_freelist = p = hcb->cch_buf; - - for ( q=p+1; (u64)(q + 1) <= (u64)hcb->cch_buf + hcb->cch_sz; - p++, q++ ) { - p->next = q; - } - p->next = NULL; -} - -static thash_data_t *cch_alloc(thash_cb_t *hcb) -{ - thash_cch_mem_t *p; - - if ( (p = hcb->cch_freelist) != NULL ) { - hcb->cch_freelist = p->next; - } - return &(p->data); -} - -static void cch_free(thash_cb_t *hcb, thash_data_t *cch) -{ - thash_cch_mem_t *p = (thash_cch_mem_t*)cch; - - p->next = hcb->cch_freelist; - hcb->cch_freelist = p; -} - -/* - * Check to see if the address rid:va is translated by the TLB - */ -static int __is_translated(thash_data_t *tlb, u64 rid, u64 va, CACHE_LINE_TYPE cl) -{ - u64 size1,sa1,ea1; - - if ( tlb->rid != rid || tlb->cl != cl ) - return 0; - size1 = PSIZE(tlb->ps); - sa1 = tlb->vadr & ~(size1-1); // mask the low address bits - ea1 = sa1 + size1; - - if ( va >= sa1 && (va < ea1 || ea1 == 0) ) - return 1; - else - return 0; -} - -/* - * Only for TLB format. - */ -static int -__is_tlb_overlap(thash_cb_t *hcb,thash_data_t *entry,int rid, char cl, u64 sva, u64 eva) -{ - uint64_t size1,size2,sa1,ea1,ea2; - - if ( entry->invalid || entry->rid != rid || entry->cl != cl ) { - return 0; - } - size1=PSIZE(entry->ps); - sa1 = entry->vadr & ~(size1-1); // mask the low address bits - ea1 = sa1 + size1; - if ( (sva >= ea1 && ea1 != 0) || (eva <= sa1 && eva != 0) ) - return 0; - else - return 1; - -} - -static void __rem_tr (thash_cb_t *hcb, thash_data_t *tr) -{ - if ( hcb->remove_notifier ) { - (hcb->remove_notifier)(hcb,tr); - } - tr->invalid = 1; -} - -static inline void __set_tr (thash_data_t *tr, thash_data_t *data, int idx) -{ - *tr = *data; - tr->tr_idx = idx; -} - - -static void __init_tr(thash_cb_t *hcb) -{ - int i; - thash_data_t *tr; - - for ( i=0, tr = &ITR(hcb,0); i<NITRS; i++ ) { - tr[i].invalid = 1; - } - for ( i=0, tr = &DTR(hcb,0); i<NDTRS; i++ ) { - tr[i].invalid = 1; - } -} - -/* - * Replace TR entry. - */ -static void rep_tr(thash_cb_t *hcb,thash_data_t *insert, int idx) -{ - thash_data_t *tr; - - if ( insert->cl == ISIDE_TLB ) { - tr = &ITR(hcb,idx); - } - else { - tr = &DTR(hcb,idx); - } - if ( !INVALID_TLB(tr) ) { - __rem_tr(hcb, tr); - } - __set_tr (tr, insert, idx); -} - -/* - * remove TR entry. - */ -static void rem_tr(thash_cb_t *hcb,CACHE_LINE_TYPE cl, int idx) -{ - thash_data_t *tr; - - if ( cl == ISIDE_TLB ) { - tr = &ITR(hcb,idx); - } - else { - tr = &DTR(hcb,idx); - } - if ( !INVALID_TLB(tr) ) { - __rem_tr(hcb, tr); - } -} - -/* - * Delete an thash entry in collision chain. - * prev: the previous entry. - * rem: the removed entry. - */ -static void __rem_chain(thash_cb_t *hcb/*, thash_data_t *prev*/, thash_data_t *rem) -{ - //prev->next = rem->next; - if ( hcb->remove_notifier ) { - (hcb->remove_notifier)(hcb,rem); - } - cch_free (hcb, rem); -} - -/* - * Delete an thash entry leading collision chain. - */ -static void __rem_hash_head(thash_cb_t *hcb, thash_data_t *hash) -{ - thash_data_t *next=hash->next; - - if ( hcb->remove_notifier ) { - (hcb->remove_notifier)(hcb,hash); - } - if ( next != NULL ) { - *hash = *next; - cch_free (hcb, next); - } - else { - INVALIDATE_HASH(hcb, hash); - } -} - -thash_data_t *__vtr_lookup(thash_cb_t *hcb, - u64 rid, u64 va, - CACHE_LINE_TYPE cl) -{ - thash_data_t *tr; - int num,i; - - if ( cl == ISIDE_TLB ) { - tr = &ITR(hcb,0); - num = NITRS; - } - else { - tr = &DTR(hcb,0); - num = NDTRS; - } - for ( i=0; i<num; i++ ) { - if ( !INVALID_ENTRY(hcb,&tr[i]) && - __is_translated(&tr[i], rid, va, cl) ) - return &tr[i]; - } - return NULL; -} - - -/* - * Find overlap VHPT entry within current collision chain - * base on internal priv info. - */ -static inline thash_data_t* _vhpt_next_overlap_in_chain(thash_cb_t *hcb) -{ - thash_data_t *cch; - thash_internal_t *priv = &hcb->priv; - - - for (cch=priv->cur_cch; cch; cch = cch->next) { - if ( priv->tag == cch->etag ) { - return cch; - } - } - return NULL; -} - -/* - * Find overlap TLB/VHPT entry within current collision chain - * base on internal priv info. - */ -static thash_data_t *_vtlb_next_overlap_in_chain(thash_cb_t *hcb) -{ - thash_data_t *cch; - thash_internal_t *priv = &hcb->priv; - - /* Find overlap TLB entry */ - for (cch=priv->cur_cch; cch; cch = cch->next) { - if ( ( cch->tc ? priv->s_sect.tc : priv->s_sect.tr ) && - __is_tlb_overlap(hcb, cch, priv->rid, priv->cl, - priv->_curva, priv->_eva) ) { - return cch; - } - } - return NULL; -} - -/* - * Get the machine format of VHPT entry. - * PARAS: - * 1: tlb: means the tlb format hash entry converting to VHPT. - * 2: va means the guest virtual address that must be coverd by - * the translated machine VHPT. - * 3: vhpt: means the machine format VHPT converting from tlb. - * NOTES: - * 1: In case of the machine address is discontiguous, - * "tlb" needs to be covered by several machine VHPT. va - * is used to choice one of them. - * 2: Foreign map is supported in this API. - * RETURN: - * 0/1: means successful or fail. - * - */ -int __tlb_to_vhpt(thash_cb_t *hcb, - thash_data_t *tlb, u64 va, - thash_data_t *vhpt) -{ - u64 pages,mfn; - ia64_rr vrr; - - ASSERT ( hcb->ht == THASH_VHPT ); - vrr = (hcb->get_rr_fn)(hcb->vcpu,va); - pages = PSIZE(vrr.ps) >> PAGE_SHIFT; - mfn = (hcb->vs->get_mfn)(DOMID_SELF,tlb->ppn, pages); - if ( mfn == INVALID_MFN ) return 0; - - // TODO with machine discontinuous address space issue. - vhpt->etag = (hcb->vs->tag_func)( hcb->pta, - tlb->vadr, tlb->rid, tlb->ps); - //vhpt->ti = 0; - vhpt->itir = tlb->itir & ~ITIR_RV_MASK; - vhpt->page_flags = tlb->page_flags & ~PAGE_FLAGS_RV_MASK; - vhpt->ppn = mfn; - vhpt->next = 0; - return 1; -} - - -/* - * Insert an entry to hash table. - * NOTES: - * 1: TLB entry may be TR, TC or Foreign Map. For TR entry, - * itr[]/dtr[] need to be updated too. - * 2: Inserting to collision chain may trigger recycling if - * the buffer for collision chain is empty. - * 3: The new entry is inserted at the next of hash table. - * (I.e. head of the collision chain) - * 4: The buffer holding the entry is allocated internally - * from cch_buf or just in the hash table. - * 5: Return the entry in hash table or collision chain. - * 6: Input parameter, entry, should be in TLB format. - * I.e. Has va, rid, ps... - * 7: This API is invoked by emulating ITC/ITR and tlb_miss. - * - */ - -void thash_tr_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va, int idx) -{ - if ( hcb->ht != THASH_TLB || entry->tc ) { - panic("wrong parameter\n"); - } - entry->vadr = PAGEALIGN(entry->vadr,entry->ps); - entry->ppn = PAGEALIGN(entry->ppn, entry->ps-12); - rep_tr(hcb, entry, idx); - return ; -} - -thash_data_t *__alloc_chain(thash_cb_t *hcb,thash_data_t *entry) -{ - thash_data_t *cch; - - cch = cch_alloc(hcb); - if(cch == NULL){ - // recycle - if ( hcb->recycle_notifier ) { - hcb->recycle_notifier(hcb,(u64)entry); - } - thash_purge_all(hcb); - cch = cch_alloc(hcb); - } - return cch; -} - -/* - * Insert an entry into hash TLB or VHPT. - * NOTES: - * 1: When inserting VHPT to thash, "va" is a must covered - * address by the inserted machine VHPT entry. - * 2: The format of entry is always in TLB. - * 3: The caller need to make sure the new entry will not overlap - * with any existed entry. - */ -void vtlb_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) -{ - thash_data_t *hash_table, *cch; - int flag; - ia64_rr vrr; - u64 gppn; - u64 ppns, ppne; - - hash_table = (hcb->hash_func)(hcb->pta, - va, entry->rid, entry->ps); - if( INVALID_ENTRY(hcb, hash_table) ) { - *hash_table = *entry; - hash_table->next = 0; - } - else { - // TODO: Add collision chain length limitation. - cch = __alloc_chain(hcb,entry); - - *cch = *hash_table; - *hash_table = *entry; - hash_table->next = cch; - } - if(hcb->vcpu->domain->domain_id==0){ - thash_insert(hcb->ts->vhpt, entry, va); - return; - } - flag = 1; - gppn = (POFFSET(va,entry->ps)|PAGEALIGN((entry->ppn<<12),entry->ps))>>PAGE_SHIFT; - ppns = PAGEALIGN((entry->ppn<<12),entry->ps); - ppne = ppns + PSIZE(entry->ps); - if(((ppns<=0xa0000)&&(ppne>0xa0000))||((ppne>0xc0000)&&(ppns<=0xc0000))) - flag = 0; - if((__gpfn_is_mem(hcb->vcpu->domain, gppn)&&flag)) - thash_insert(hcb->ts->vhpt, entry, va); - return ; -} - -static void vhpt_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) -{ - thash_data_t *hash_table, *cch; - ia64_rr vrr; - - hash_table = (hcb->hash_func)(hcb->pta, - va, entry->rid, entry->ps); - if( INVALID_ENTRY(hcb, hash_table) ) { - if ( !__tlb_to_vhpt(hcb, entry, va, hash_table) ) { - panic("Can't convert to machine VHPT entry\n"); - } - hash_table->next = 0; - } - else { - // TODO: Add collision chain length limitation. - cch = __alloc_chain(hcb,entry); - - *cch = *hash_table; - if ( !__tlb_to_vhpt(hcb, entry, va, hash_table) ) { - panic("Can't convert to machine VHPT entry\n"); - } - hash_table->next = cch; - if(hash_table->tag==hash_table->next->tag) - while(1); - } - return /*hash_table*/; -} - -void thash_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) -{ - thash_data_t *hash_table; - ia64_rr vrr; - - vrr = (hcb->get_rr_fn)(hcb->vcpu,entry->vadr); - if ( entry->ps != vrr.ps && entry->tc ) { - panic("Not support for multiple page size now\n"); - } - entry->vadr = PAGEALIGN(entry->vadr,entry->ps); - entry->ppn = PAGEALIGN(entry->ppn, entry->ps-12); - (hcb->ins_hash)(hcb, entry, va); - -} - -static void rem_thash(thash_cb_t *hcb, thash_data_t *entry) -{ - thash_data_t *hash_table, *p, *q; - thash_internal_t *priv = &hcb->priv; - int idx; - - hash_table = priv->hash_base; - if ( hash_table == entry ) { -// if ( PURGABLE_ENTRY(hcb, entry) ) { - __rem_hash_head (hcb, entry); -// } - return ; - } - // remove from collision chain - p = hash_table; - for ( q=p->next; q; q = p->next ) { - if ( q == entry ){ -// if ( PURGABLE_ENTRY(hcb,q ) ) { - p->next = q->next; - __rem_chain(hcb, entry); -// } - return ; - } - p = q; - } - panic("Entry not existed or bad sequence\n"); -} - -static void rem_vtlb(thash_cb_t *hcb, thash_data_t *entry) -{ - thash_data_t *hash_table, *p, *q; - thash_internal_t *priv = &hcb->priv; - int idx; - - if ( !entry->tc ) { - return rem_tr(hcb, entry->cl, entry->tr_idx); - } - rem_thash(hcb, entry); -} - -int cch_depth=0; -/* - * Purge the collision chain starting from cch. - * NOTE: - * For those UN-Purgable entries(FM), this function will return - * the head of left collision chain. - */ -static thash_data_t *thash_rem_cch(thash_cb_t *hcb, thash_data_t *cch) -{ - thash_data_t *next; - - if ( ++cch_depth > MAX_CCH_LENGTH ) { - printf ("cch length > MAX_CCH_LENGTH, exceed the expected length\n"); - while(1); - } - if ( cch -> next ) { - next = thash_rem_cch(hcb, cch->next); - } - else { - next = NULL; - } - if ( PURGABLE_ENTRY(hcb, cch) ) { - __rem_chain(hcb, cch); - return next; - } - else { - cch->next = next; - return cch; - } -} - -/* - * Purge one hash line (include the entry in hash table). - * Can only be called by thash_purge_all. - * Input: - * hash: The head of collision chain (hash table) - * - */ -static void thash_rem_line(thash_cb_t *hcb, thash_data_t *hash) -{ - if ( INVALID_ENTRY(hcb, hash) ) return; - - if ( hash->next ) { - cch_depth = 0; - hash->next = thash_rem_cch(hcb, hash->next); - } - // Then hash table itself. - if ( PURGABLE_ENTRY(hcb, hash) ) { - __rem_hash_head(hcb, hash); - } -} - - -/* - * Find an overlap entry in hash table and its collision chain. - * Refer to SDM2 4.1.1.4 for overlap definition. - * PARAS: - * 1: in: TLB format entry, rid:ps must be same with vrr[]. - * va & ps identify the address space for overlap lookup - * 2: section can be combination of TR, TC and FM. (THASH_SECTION_XX) - * 3: cl means I side or D side. - * RETURNS: - * NULL to indicate the end of findings. - * NOTES: - * - */ -thash_data_t *thash_find_overlap(thash_cb_t *hcb, - thash_data_t *in, search_section_t s_sect) -{ - return (hcb->find_overlap)(hcb, in->vadr, - PSIZE(in->ps), in->rid, in->cl, s_sect); -} - -static thash_data_t *vtlb_find_overlap(thash_cb_t *hcb, - u64 va, u64 size, int rid, char cl, search_section_t s_sect) -{ - thash_data_t *hash_table; - thash_internal_t *priv = &hcb->priv; - u64 tag; - ia64_rr vrr; - - priv->_curva = va & ~(size-1); - priv->_eva = priv->_curva + size; - priv->rid = rid; - vrr = (hcb->get_rr_fn)(hcb->vcpu,va); - priv->ps = vrr.ps; - hash_table = (hcb->hash_func)(hcb->pta, - priv->_curva, rid, priv->ps); - - priv->s_sect = s_sect; - priv->cl = cl; - priv->_tr_idx = 0; - priv->hash_base = hash_table; - priv->cur_cch = hash_table; - return (hcb->next_overlap)(hcb); -} - -static thash_data_t *vhpt_find_overlap(thash_cb_t *hcb, - u64 va, u64 size, int rid, char cl, search_section_t s_sect) -{ - thash_data_t *hash_table; - thash_internal_t *priv = &hcb->priv; - u64 tag; - ia64_rr vrr; - - priv->_curva = va & ~(size-1); - priv->_eva = priv->_curva + size; - priv->rid = rid; - vrr = (hcb->get_rr_fn)(hcb->vcpu,va); - priv->ps = vrr.ps; - hash_table = (hcb->hash_func)( hcb->pta, - priv->_curva, rid, priv->ps); - tag = (hcb->vs->tag_func)( hcb->pta, - priv->_curva, rid, priv->ps); - - priv->tag = tag; - priv->hash_base = hash_table; - priv->cur_cch = hash_table; - return (hcb->next_overlap)(hcb); -} - - -static thash_data_t *vtr_find_next_overlap(thash_cb_t *hcb) -{ - thash_data_t *tr; - thash_internal_t *priv = &hcb->priv; - int num; - - if ( priv->cl == ISIDE_TLB ) { - num = NITRS; - tr = &ITR(hcb,0); - } - else { - num = NDTRS; - tr = &DTR(hcb,0); - } - for (; priv->_tr_idx < num; priv->_tr_idx ++ ) { - if ( __is_tlb_overlap(hcb, &tr[priv->_tr_idx], - priv->rid, priv->cl, - priv->_curva, priv->_eva) ) { - return &tr[priv->_tr_idx++]; - } - } - return NULL; -} - -/* - * Similar with vtlb_next_overlap but find next entry. - * NOTES: - * Intermediate position information is stored in hcb->priv. - */ -static thash_data_t *vtlb_next_overlap(thash_cb_t *hcb) -{ - thash_data_t *ovl; - thash_internal_t *priv = &hcb->priv; - u64 addr,rr_psize; - ia64_rr vrr; - - if ( priv->s_sect.tr ) { - ovl = vtr_find_next_overlap (hcb); - if ( ovl ) return ovl; - priv->s_sect.tr = 0; - } - if ( priv->s_sect.v == 0 ) return NULL; - vrr = (hcb->get_rr_fn)(hcb->vcpu,priv->_curva); - rr_psize = PSIZE(vrr.ps); - - while ( priv->_curva < priv->_eva ) { - if ( !INVALID_ENTRY(hcb, priv->hash_base) ) { - ovl = _vtlb_next_overlap_in_chain(hcb); - if ( ovl ) { - priv->cur_cch = ovl->next; - return ovl; - } - } - priv->_curva += rr_psize; - priv->hash_base = (hcb->hash_func)( hcb->pta, - priv->_curva, priv->rid, priv->ps); - priv->cur_cch = priv->hash_base; - } - return NULL; -} - -static thash_data_t *vhpt_next_overlap(thash_cb_t *hcb) -{ - thash_data_t *ovl; - thash_internal_t *priv = &hcb->priv; - u64 addr,rr_psize; - ia64_rr vrr; - - vrr = (hcb->get_rr_fn)(hcb->vcpu,priv->_curva); - rr_psize = PSIZE(vrr.ps); - - while ( priv->_curva < priv->_eva ) { - if ( !INVALID_ENTRY(hcb, priv->hash_base) ) { - ovl = _vhpt_next_overlap_in_chain(hcb); - if ( ovl ) { - priv->cur_cch = ovl->next; - return ovl; - } - } - priv->_curva += rr_psize; - priv->hash_base = (hcb->hash_func)( hcb->pta, - priv->_curva, priv->rid, priv->ps); - priv->tag = (hcb->vs->tag_func)( hcb->pta, - priv->_curva, priv->rid, priv->ps); - priv->cur_cch = priv->hash_base; - } - return NULL; -} - - -/* - * Find and purge overlap entries in hash table and its collision chain. - * PARAS: - * 1: in: TLB format entry, rid:ps must be same with vrr[]. - * rid, va & ps identify the address space for purge - * 2: section can be combination of TR, TC and FM. (thash_SECTION_XX) - * 3: cl means I side or D side. - * NOTES: - * - */ -void thash_purge_entries(thash_cb_t *hcb, - thash_data_t *in, search_section_t p_sect) -{ - return thash_purge_entries_ex(hcb, in->rid, in->vadr, - in->ps, p_sect, in->cl); -} - -void thash_purge_entries_ex(thash_cb_t *hcb, - u64 rid, u64 va, u64 ps, - search_section_t p_sect, - CACHE_LINE_TYPE cl) -{ - thash_data_t *ovl; - - ovl = (hcb->find_overlap)(hcb, va, PSIZE(ps), rid, cl, p_sect); - while ( ovl != NULL ) { - (hcb->rem_hash)(hcb, ovl); - ovl = (hcb->next_overlap)(hcb); - }; -} - -/* - * Purge overlap TCs and then insert the new entry to emulate itc ops. - * Notes: Only TC entry can purge and insert. - */ -void thash_purge_and_insert(thash_cb_t *hcb, thash_data_t *in) -{ - thash_data_t *ovl; - search_section_t sections; - -#ifdef XEN_DEBUGGER - vrr = (hcb->get_rr_fn)(hcb->vcpu,in->vadr); - if ( in->ps != vrr.ps || hcb->ht != THASH_TLB || !in->tc ) { - panic ("Oops, wrong call for purge_and_insert\n"); - return; - } -#endif - in->vadr = PAGEALIGN(in->vadr,in->ps); - in->ppn = PAGEALIGN(in->ppn, in->ps-12); - sections.tr = 0; - sections.tc = 1; - ovl = (hcb->find_overlap)(hcb, in->vadr, PSIZE(in->ps), - in->rid, in->cl, sections); - if(ovl) - (hcb->rem_hash)(hcb, ovl); -#ifdef XEN_DEBUGGER - ovl = (hcb->next_overlap)(hcb); - if ( ovl ) { - panic ("Oops, 2+ overlaps for purge_and_insert\n"); - return; - } -#endif - (hcb->ins_hash)(hcb, in, in->vadr); -} - -/* - * Purge all TCs or VHPT entries including those in Hash table. - * - */ - -// TODO: add sections. -void thash_purge_all(thash_cb_t *hcb) -{ - thash_data_t *hash_table; - -#ifdef VTLB_DEBUG - extern u64 sanity_check; - static u64 statistics_before_purge_all=0; - if ( statistics_before_purge_all ) { - sanity_check = 1; - check_vtlb_sanity(hcb); - } -#endif - - hash_table = (thash_data_t*)((u64)hcb->hash + hcb->hash_sz); - - for (--hash_table;(u64)hash_table >= (u64)hcb->hash;hash_table--) { - thash_rem_line(hcb, hash_table); - } -} - - -/* - * Lookup the hash table and its collision chain to find an entry - * covering this address rid:va or the entry. - * - * INPUT: - * in: TLB format for both VHPT & TLB. - */ -thash_data_t *vtlb_lookup(thash_cb_t *hcb, - thash_data_t *in) -{ - return vtlb_lookup_ex(hcb, in->rid, in->vadr, in->cl); -} - -thash_data_t *vtlb_lookup_ex(thash_cb_t *hcb, - u64 rid, u64 va, - CACHE_LINE_TYPE cl) -{ - thash_data_t *hash_table, *cch; - u64 tag; - ia64_rr vrr; - - ASSERT ( hcb->ht == THASH_VTLB ); - - cch = __vtr_lookup(hcb, rid, va, cl);; - if ( cch ) return cch; - - vrr = (hcb->get_rr_fn)(hcb->vcpu,va); - hash_table = (hcb->hash_func)( hcb->pta,va, rid, vrr.ps); - - if ( INVALID_ENTRY(hcb, hash_table ) ) - return NULL; - - - for (cch=hash_table; cch; cch = cch->next) { - if ( __is_translated(cch, rid, va, cl) ) - return cch; - } - return NULL; -} - -/* - * Lock/Unlock TC if found. - * NOTES: Only the page in prefered size can be handled. - * return: - * 1: failure - * 0: success - */ -int thash_lock_tc(thash_cb_t *hcb, u64 va, u64 size, int rid, char cl, int lock) -{ - thash_data_t *ovl; - search_section_t sections; - - sections.tr = 1; - sections.tc = 1; - ovl = (hcb->find_overlap)(hcb, va, size, rid, cl, sections); - if ( ovl ) { - if ( !ovl->tc ) { -// panic("Oops, TR for lock\n"); - return 0; - } - else if ( lock ) { - if ( ovl->locked ) { - DPRINTK("Oops, already locked entry\n"); - } - ovl->locked = 1; - } - else if ( !lock ) { - if ( !ovl->locked ) { - DPRINTK("Oops, already unlocked entry\n"); - } - ovl->locked = 0; - } - return 0; - } - return 1; -} - -/* - * Notifier when TLB is deleted from hash table and its collision chain. - * NOTES: - * The typical situation is that TLB remove needs to inform - * VHPT to remove too. - * PARAS: - * 1: hcb is TLB object. - * 2: The format of entry is always in TLB. - * - */ -void tlb_remove_notifier(thash_cb_t *hcb, thash_data_t *entry) -{ - thash_cb_t *vhpt; - search_section_t s_sect; - - s_sect.v = 0; - thash_purge_entries(hcb->ts->vhpt, entry, s_sect); - machine_tlb_purge(entry->rid, entry->vadr, entry->ps); -} - -/* - * Initialize internal control data before service. - */ -void thash_init(thash_cb_t *hcb, u64 sz) -{ - thash_data_t *hash_table; - - cch_mem_init (hcb); - hcb->magic = THASH_CB_MAGIC; - hcb->pta.val = hcb->hash; - hcb->pta.vf = 1; - hcb->pta.ve = 1; - hcb->pta.size = sz; - hcb->get_rr_fn = vmmu_get_rr; - ASSERT ( hcb->hash_sz % sizeof(thash_data_t) == 0 ); - if ( hcb->ht == THASH_TLB ) { - hcb->remove_notifier = tlb_remove_notifier; - hcb->find_overlap = vtlb_find_overlap; - hcb->next_overlap = vtlb_next_overlap; - hcb->rem_hash = rem_vtlb; - hcb->ins_hash = vtlb_insert; - __init_tr(hcb); - } - else { - hcb->remove_notifier = NULL; - hcb->find_overlap = vhpt_find_overlap; - hcb->next_overlap = vhpt_next_overlap; - hcb->rem_hash = rem_thash; - hcb->ins_hash = vhpt_insert; - } - hash_table = (thash_data_t*)((u64)hcb->hash + hcb->hash_sz); - - for (--hash_table;(u64)hash_table >= (u64)hcb->hash;hash_table--) { - INVALIDATE_HASH(hcb,hash_table); - } -} - -#ifdef VTLB_DEBUG -static u64 cch_length_statistics[MAX_CCH_LENGTH+1]; -u64 sanity_check=0; -u64 vtlb_chain_sanity(thash_cb_t *vtlb, thash_cb_t *vhpt, thash_data_t *hash) -{ - thash_data_t *cch; - thash_data_t *ovl; - search_section_t s_sect; - u64 num=0; - - s_sect.v = 0; - for (cch=hash; cch; cch=cch->next) { - ovl = thash_find_overlap(vhpt, cch, s_sect); - while ( ovl != NULL ) { - ovl->checked = 1; - ovl = (vhpt->next_overlap)(vhpt); - }; - num ++; - } - if ( num >= MAX_CCH_LENGTH ) { - cch_length_statistics[MAX_CCH_LENGTH] ++; - } - else { - cch_length_statistics[num] ++; - } - return num; -} - -void check_vtlb_sanity(thash_cb_t *vtlb) -{ -// struct pfn_info *page; - u64 hash_num, i, psr; - static u64 check_ok_num, check_fail_num,check_invalid; -// void *vb1, *vb2; - thash_data_t *hash, *cch; - thash_data_t *ovl; - search_section_t s_sect; - thash_cb_t *vhpt = vtlb->ts->vhpt; - u64 invalid_ratio; - - if ( sanity_check == 0 ) return; - sanity_check --; - s_sect.v = 0; -// page = alloc_domheap_pages (NULL, VCPU_TLB_ORDER, 0); -// if ( page == NULL ) { -// panic("No enough contiguous memory for init_domain_mm\n"); -// }; -// vb1 = page_to_virt(page); -// printf("Allocated page=%lp vbase=%lp\n", page, vb1); -// vb2 = vb1 + vtlb->hash_sz; - hash_num = vhpt->hash_sz / sizeof(thash_data_t); -// printf("vb2=%lp, size=%lx hash_num=%lx\n", vb2, vhpt->hash_sz, hash_num); - printf("vtlb=%lp, hash=%lp size=0x%lx; vhpt=%lp, hash=%lp size=0x%lx\n", - vtlb, vtlb->hash,vtlb->hash_sz, - vhpt, vhpt->hash, vhpt->hash_sz); - //memcpy(vb1, vtlb->hash, vtlb->hash_sz); - //memcpy(vb2, vhpt->hash, vhpt->hash_sz); - for ( i=0; i < sizeof(cch_length_statistics)/sizeof(cch_length_statistics[0]); i++ ) { - cch_length_statistics[i] = 0; - } - - local_irq_save(psr); - - hash = vhpt->hash; - for (i=0; i < hash_num; i++) { - if ( !INVALID_ENTRY(vhpt, hash) ) { - for ( cch= hash; cch; cch=cch->next) { - cch->checked = 0; - } - } - hash ++; - } - printf("Done vhpt clear checked flag, hash_num=0x%lx\n", hash_num); - check_invalid = 0; - check_ok_num=0; - hash = vtlb->hash; - for ( i=0; i< hash_num; i++ ) { - if ( !INVALID_ENTRY(vtlb, hash) ) { - check_ok_num += vtlb_chain_sanity(vtlb, vhpt, hash); - } - else { - check_invalid++; - } - hash ++; - } - printf("Done vtlb entry check, hash=%lp\n", hash); - printf("check_ok_num = 0x%lx check_invalid=0x%lx\n", check_ok_num,check_invalid); - invalid_ratio = 1000*check_invalid / hash_num; - printf("%02ld.%01ld%% entries are invalid\n", - invalid_ratio/10, invalid_ratio % 10 ); - for (i=0; i<NDTRS; i++) { - ovl = thash_find_overlap(vhpt, &vtlb->ts->dtr[i], s_sect); - while ( ovl != NULL ) { - ovl->checked = 1; - ovl = (vhpt->next_overlap)(vhpt); - }; - } - printf("Done dTR\n"); - for (i=0; i<NITRS; i++) { - ovl = thash_find_overlap(vhpt, &vtlb->ts->itr[i], s_sect); - while ( ovl != NULL ) { - ovl->checked = 1; - ovl = (vhpt->next_overlap)(vhpt); - }; - } - printf("Done iTR\n"); - check_fail_num = 0; - check_invalid = 0; - check_ok_num=0; - hash = vhpt->hash; - for (i=0; i < hash_num; i++) { - if ( !INVALID_ENTRY(vhpt, hash) ) { - for ( cch= hash; cch; cch=cch->next) { - if ( !cch->checked ) { - printf ("!!!Hash=%lp cch=%lp not within vtlb\n", hash, cch); - check_fail_num ++; - } - else { - check_ok_num++; - } - } - } - else { - check_invalid ++; - } - hash ++; - } - local_irq_restore(psr); - printf("check_ok_num=0x%lx check_fail_num=0x%lx check_invalid=0x%lx\n", - check_ok_num, check_fail_num, check_invalid); - //memcpy(vtlb->hash, vb1, vtlb->hash_sz); - //memcpy(vhpt->hash, vb2, vhpt->hash_sz); - printf("The statistics of collision chain length is listed\n"); - for ( i=0; i < sizeof(cch_length_statistics)/sizeof(cch_length_statistics[0]); i++ ) { - printf("CCH length=%02ld, chain number=%ld\n", i, cch_length_statistics[i]); - } -// free_domheap_pages(page, VCPU_TLB_ORDER); - printf("Done check_vtlb\n"); -} - -void dump_vtlb(thash_cb_t *vtlb) -{ - static u64 dump_vtlb=0; - thash_data_t *hash, *cch, *tr; - u64 hash_num,i; - - if ( dump_vtlb == 0 ) return; - dump_vtlb --; - hash_num = vtlb->hash_sz / sizeof(thash_data_t); - hash = vtlb->hash; - - printf("Dump vTC\n"); - for ( i = 0; i < hash_num; i++ ) { - if ( !INVALID_ENTRY(vtlb, hash) ) { - printf("VTLB at hash=%lp\n", hash); - for (cch=hash; cch; cch=cch->next) { - printf("Entry %lp va=%lx ps=%lx rid=%lx\n", - cch, cch->vadr, cch->ps, cch->rid); - } - } - hash ++; - } - printf("Dump vDTR\n"); - for (i=0; i<NDTRS; i++) { - tr = &DTR(vtlb,i); - printf("Entry %lp va=%lx ps=%lx rid=%lx\n", - tr, tr->vadr, tr->ps, tr->rid); - } - printf("Dump vITR\n"); - for (i=0; i<NITRS; i++) { - tr = &ITR(vtlb,i); - printf("Entry %lp va=%lx ps=%lx rid=%lx\n", - tr, tr->vadr, tr->ps, tr->rid); - } - printf("End of vTLB dump\n"); -} -#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xen.lds.S --- a/xen/arch/ia64/xen.lds.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,251 +0,0 @@ -#include <linux/config.h> - -#include <asm/cache.h> -#include <asm/ptrace.h> -#include <asm/system.h> -#include <asm/pgtable.h> - -#define LOAD_OFFSET (KERNEL_START - KERNEL_TR_PAGE_SIZE) -#include <asm-generic/vmlinux.lds.h> - -OUTPUT_FORMAT("elf64-ia64-little") -OUTPUT_ARCH(ia64) -ENTRY(phys_start) -jiffies = jiffies_64; -PHDRS { - code PT_LOAD; - percpu PT_LOAD; - data PT_LOAD; -} -SECTIONS -{ - /* Sections to be discarded */ - /DISCARD/ : { - *(.exit.text) - *(.exit.data) - *(.exitcall.exit) - *(.IA_64.unwind.exit.text) - *(.IA_64.unwind_info.exit.text) - } - - v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ - phys_start = _start - LOAD_OFFSET; - - code : { } :code - . = KERNEL_START; - - _text = .; - _stext = .; - - .text : AT(ADDR(.text) - LOAD_OFFSET) - { - *(.text.ivt) - *(.text) - SCHED_TEXT - LOCK_TEXT - *(.gnu.linkonce.t*) - } - .text2 : AT(ADDR(.text2) - LOAD_OFFSET) - { *(.text2) } -#ifdef CONFIG_SMP - .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) - { *(.text.lock) } -#endif - _etext = .; - - /* Read-only data */ - - /* Exception table */ - . = ALIGN(16); - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) - { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } - - .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) - { - __start___vtop_patchlist = .; - *(.data.patch.vtop) - __end___vtop_patchlist = .; - } - - .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) - { - __start___mckinley_e9_bundles = .; - *(.data.patch.mckinley_e9) - __end___mckinley_e9_bundles = .; - } - - /* Global data */ - _data = .; - -#if defined(CONFIG_IA64_GENERIC) - /* Machine Vector */ - . = ALIGN(16); - .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) - { - machvec_start = .; - *(.machvec) - machvec_end = .; - } -#endif - - /* Unwind info & table: */ - . = ALIGN(8); - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) - { *(.IA_64.unwind_info*) } - .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) - { - __start_unwind = .; - *(.IA_64.unwind*) - __end_unwind = .; - } - - RODATA - - .opd : AT(ADDR(.opd) - LOAD_OFFSET) - { *(.opd) } - - /* Initialization code and data: */ - - . = ALIGN(PAGE_SIZE); - __init_begin = .; - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) - { - _sinittext = .; - *(.init.text) - _einittext = .; - } - - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) - { *(.init.data) } - - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) - { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } - - . = ALIGN(16); - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) - { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) - { - __initcall_start = .; - *(.initcall1.init) - *(.initcall2.init) - *(.initcall3.init) - *(.initcall4.init) - *(.initcall5.init) - *(.initcall6.init) - *(.initcall7.init) - __initcall_end = .; - } - __con_initcall_start = .; - .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) - { *(.con_initcall.init) } - __con_initcall_end = .; - __security_initcall_start = .; - .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) - { *(.security_initcall.init) } - __security_initcall_end = .; - . = ALIGN(PAGE_SIZE); - __init_end = .; - - /* The initial task and kernel stack */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) - { *(.data.init_task) } - - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) - { *(__special_page_section) - __start_gate_section = .; - *(.data.gate) - __stop_gate_section = .; - } - . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */ - - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) - { *(.data.cacheline_aligned) } - - /* Per-cpu data: */ - percpu : { } :percpu - . = ALIGN(PERCPU_PAGE_SIZE); - __phys_per_cpu_start = .; - .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET) - { - __per_cpu_start = .; - *(.data.percpu) - __per_cpu_end = .; - } - . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */ - - data : { } :data - .data : AT(ADDR(.data) - LOAD_OFFSET) - { *(.data) *(.data1) *(.gnu.linkonce.d*) CONSTRUCTORS } - - . = ALIGN(16); /* gp must be 16-byte aligned for exc. table */ - .got : AT(ADDR(.got) - LOAD_OFFSET) - { *(.got.plt) *(.got) } - __gp = ADDR(.got) + 0x200000; - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) - { *(.sdata) *(.sdata1) *(.srdata) } - _edata = .; - _bss = .; - .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) - { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - LOAD_OFFSET) - { *(.bss) *(COMMON) } - - _end = .; - - code : { } :code - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ - /* Discard them for now since Intel SoftSDV cannot handle them. - .comment 0 : { *(.comment) } - .note 0 : { *(.note) } - */ - /DISCARD/ : { *(.comment) } - /DISCARD/ : { *(.note) } -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xenasm.S --- a/xen/arch/ia64/xenasm.S Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,501 +0,0 @@ -/* - * Assembly support routines for Xen/ia64 - * - * Copyright (C) 2004 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ - -#include <linux/config.h> -#include <asm/asmmacro.h> -#include <asm/processor.h> -#include <asm/pgtable.h> -#include <asm/vhpt.h> - -#if 0 -// FIXME: there's gotta be a better way... -// ski and spaski are different... moved to xenmisc.c -#define RunningOnHpSki(rx,ry,pn) \ - addl rx = 2, r0; \ - addl ry = 3, r0; \ - ;; \ - mov rx = cpuid[rx]; \ - mov ry = cpuid[ry]; \ - ;; \ - cmp.eq pn,p0 = 0, rx; \ - ;; \ - (pn) movl rx = 0x7000004 ; \ - ;; \ - (pn) cmp.ge pn,p0 = ry, rx; \ - ;; - -//int platform_is_hp_ski(void) -GLOBAL_ENTRY(platform_is_hp_ski) - mov r8 = 0 - RunningOnHpSki(r3,r9,p8) -(p8) mov r8 = 1 - br.ret.sptk.many b0 -END(platform_is_hp_ski) -#endif - -// Change rr7 to the passed value while ensuring -// Xen is mapped into the new region. -// in0: new rr7 value -// in1: Xen virtual address of shared info (to be pinned) -#define PSR_BITS_TO_CLEAR \ - (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ - IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ - IA64_PSR_DFL | IA64_PSR_DFH) -// FIXME? Note that this turns off the DB bit (debug) -#define PSR_BITS_TO_SET IA64_PSR_BN - -//extern void ia64_new_rr7(unsigned long rid,void *shared_info, void *shared_arch_info); -GLOBAL_ENTRY(ia64_new_rr7) - // not sure this unwind statement is correct... - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1) - alloc loc1 = ar.pfs, 3, 8, 0, 0 -1: { - mov r28 = in0 // copy procedure index - mov r8 = ip // save ip to compute branch - mov loc0 = rp // save rp - };; - .body - movl loc2=PERCPU_ADDR - ;; - tpa loc2=loc2 // grab this BEFORE changing rr7 - ;; -#if VHPT_ENABLED - movl loc6=VHPT_ADDR - ;; - tpa loc6=loc6 // grab this BEFORE changing rr7 - ;; -#endif - mov loc5=in1 - ;; - tpa loc5=loc5 // grab this BEFORE changing rr7 - ;; - mov loc7=in2 // arch_vcpu_info_t - ;; - tpa loc7=loc7 // grab this BEFORE changing rr7 - ;; - mov loc3 = psr // save psr - adds r8 = 1f-1b,r8 // calculate return address for call - ;; - tpa r8=r8 // convert rp to physical - ;; - mov loc4=ar.rsc // save RSE configuration - ;; - mov ar.rsc=0 // put RSE in enforced lazy, LE mode - movl r16=PSR_BITS_TO_CLEAR - movl r17=PSR_BITS_TO_SET - ;; - or loc3=loc3,r17 // add in psr the bits to set - ;; - andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode_phys -1: - // now in physical mode with psr.i/ic off so do rr7 switch - dep r16=-1,r0,61,3 - ;; - mov rr[r16]=in0 - srlz.d - ;; - - // re-pin mappings for kernel text and data - mov r18=KERNEL_TR_PAGE_SHIFT<<2 - movl r17=KERNEL_START - ;; - rsm psr.i | psr.ic - ;; - srlz.i - ;; - ptr.i r17,r18 - ptr.d r17,r18 - ;; - mov cr.itir=r18 - mov cr.ifa=r17 - mov r16=IA64_TR_KERNEL - //mov r3=ip - movl r18=PAGE_KERNEL - ;; - dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT - ;; - or r18=r2,r18 - ;; - srlz.i - ;; - itr.i itr[r16]=r18 - ;; - itr.d dtr[r16]=r18 - ;; - - // re-pin mappings for stack (current), per-cpu, vhpt, and shared info - - // unless overlaps with KERNEL_TR - dep r18=0,r13,0,KERNEL_TR_PAGE_SHIFT - ;; - cmp.eq p7,p0=r17,r18 -(p7) br.cond.sptk .stack_overlaps - ;; - movl r25=PAGE_KERNEL - dep r21=0,r13,60,4 // physical address of "current" - ;; - or r23=r25,r21 // construct PA | page properties - mov r25=IA64_GRANULE_SHIFT<<2 - ;; - ptr.d r13,r25 - ;; - mov cr.itir=r25 - mov cr.ifa=r13 // VA of next task... - ;; - mov r25=IA64_TR_CURRENT_STACK - ;; - itr.d dtr[r25]=r23 // wire in new mapping... - ;; -.stack_overlaps: - - movl r22=PERCPU_ADDR - ;; - movl r25=PAGE_KERNEL - ;; - mov r21=loc2 // saved percpu physical address - ;; - or r23=r25,r21 // construct PA | page properties - mov r24=PERCPU_PAGE_SHIFT<<2 - ;; - ptr.d r22,r24 - ;; - mov cr.itir=r24 - mov cr.ifa=r22 - ;; - mov r25=IA64_TR_PERCPU_DATA - ;; - itr.d dtr[r25]=r23 // wire in new mapping... - ;; - -#if VHPT_ENABLED - movl r22=VHPT_ADDR - ;; - movl r25=PAGE_KERNEL - ;; - mov r21=loc6 // saved vhpt physical address - ;; - or r23=r25,r21 // construct PA | page properties - mov r24=VHPT_PAGE_SHIFT<<2 - ;; - ptr.d r22,r24 - ;; - mov cr.itir=r24 - mov cr.ifa=r22 - ;; - mov r25=IA64_TR_VHPT - ;; - itr.d dtr[r25]=r23 // wire in new mapping... - ;; -#endif - - movl r22=SHAREDINFO_ADDR - ;; - movl r25=__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RW) - ;; - mov r21=loc5 // saved sharedinfo physical address - ;; - or r23=r25,r21 // construct PA | page properties - mov r24=PAGE_SHIFT<<2 - ;; - ptr.d r22,r24 - ;; - mov cr.itir=r24 - mov cr.ifa=r22 - ;; - mov r25=IA64_TR_SHARED_INFO - ;; - itr.d dtr[r25]=r23 // wire in new mapping... - ;; - // Map for arch_vcpu_info_t - movl r22=SHARED_ARCHINFO_ADDR - ;; - movl r25=__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RW) - ;; - mov r21=loc7 // saved sharedinfo physical address - ;; - or r23=r25,r21 // construct PA | page properties - mov r24=PAGE_SHIFT<<2 - ;; - ptr.d r22,r24 - ;; - mov cr.itir=r24 - mov cr.ifa=r22 - ;; - mov r25=IA64_TR_ARCH_INFO - ;; - itr.d dtr[r25]=r23 // wire in new mapping... - ;; - - // done, switch back to virtual and return - mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode - mov psr.l = loc3 // restore init PSR - - mov ar.pfs = loc1 - mov rp = loc0 - ;; - mov ar.rsc=loc4 // restore RSE configuration - srlz.d // seralize restoration of psr.l - br.ret.sptk.many rp -END(ia64_new_rr7) - -#include "minstate.h" - -GLOBAL_ENTRY(ia64_prepare_handle_privop) - .prologue - /* - * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 - */ - mov r16=r0 - DO_SAVE_SWITCH_STACK - br.call.sptk.many rp=ia64_handle_privop // stack frame setup in ivt -.ret22: .body - DO_LOAD_SWITCH_STACK - br.cond.sptk.many rp // goes to ia64_leave_kernel -END(ia64_prepare_handle_privop) - -GLOBAL_ENTRY(ia64_prepare_handle_break) - .prologue - /* - * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 - */ - mov r16=r0 - DO_SAVE_SWITCH_STACK - br.call.sptk.many rp=ia64_handle_break // stack frame setup in ivt -.ret23: .body - DO_LOAD_SWITCH_STACK - br.cond.sptk.many rp // goes to ia64_leave_kernel -END(ia64_prepare_handle_break) - -GLOBAL_ENTRY(ia64_prepare_handle_reflection) - .prologue - /* - * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 - */ - mov r16=r0 - DO_SAVE_SWITCH_STACK - br.call.sptk.many rp=ia64_handle_reflection // stack frame setup in ivt -.ret24: .body - DO_LOAD_SWITCH_STACK - br.cond.sptk.many rp // goes to ia64_leave_kernel -END(ia64_prepare_handle_reflection) - -GLOBAL_ENTRY(__get_domain_bundle) - EX(.failure_in_get_bundle,ld8 r8=[r32],8) - ;; - EX(.failure_in_get_bundle,ld8 r9=[r32]) - ;; - br.ret.sptk.many rp - ;; -.failure_in_get_bundle: - mov r8=0 - ;; - mov r9=0 - ;; - br.ret.sptk.many rp - ;; -END(__get_domain_bundle) - -GLOBAL_ENTRY(dorfirfi) - movl r16 = XSI_IIP - movl r17 = XSI_IPSR - movl r18 = XSI_IFS - ;; - ld8 r16 = [r16] - ld8 r17 = [r17] - ld8 r18 = [r18] - ;; - mov cr.iip=r16 - mov cr.ipsr=r17 - mov cr.ifs=r18 - ;; - // fall through -END(dorfirfi) - -GLOBAL_ENTRY(dorfi) - rfi - ;; -END(dorfirfi) - -// -// Long's Peak UART Offsets -// -#define COM_TOP 0xff5e0000 -#define COM_BOT 0xff5e2000 - -// UART offsets -#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ -#define UART_INT_ENB 1 /* interrupt enable (DLAB=0) */ -#define UART_INT_ID 2 /* Interrupt ID register */ -#define UART_LINE_CTL 3 /* Line control register */ -#define UART_MODEM_CTL 4 /* Modem Control Register */ -#define UART_LSR 5 /* In: Line Status Register */ -#define UART_MSR 6 /* Modem status register */ -#define UART_DLATCH_LOW UART_TX -#define UART_DLATCH_HIGH UART_INT_ENB -#define COM1 0x3f8 -#define COM2 0x2F8 -#define COM3 0x3E8 - -/* interrupt enable bits (offset 1) */ -#define DATA_AVAIL_INT 1 -#define XMIT_HOLD_EMPTY_INT 2 -#define LINE_STAT_INT 4 -#define MODEM_STAT_INT 8 - -/* line status bits (offset 5) */ -#define REC_DATA_READY 1 -#define OVERRUN 2 -#define PARITY_ERROR 4 -#define FRAMING_ERROR 8 -#define BREAK_INTERRUPT 0x10 -#define XMIT_HOLD_EMPTY 0x20 -#define XMIT_SHIFT_EMPTY 0x40 - -// Write a single character -// input: r32 = character to be written -// output: none -GLOBAL_ENTRY(longs_peak_putc) - rsm psr.dt - movl r16 = 0x8000000000000000 + COM_TOP + UART_LSR - ;; - srlz.i - ;; - -.Chk_THRE_p: - ld1.acq r18=[r16] - ;; - - and r18 = XMIT_HOLD_EMPTY, r18 - ;; - cmp4.eq p6,p0=0,r18 - ;; - -(p6) br .Chk_THRE_p - ;; - movl r16 = 0x8000000000000000 + COM_TOP + UART_TX - ;; - st1.rel [r16]=r32 - ;; - ssm psr.dt - ;; - srlz.i - ;; - br.ret.sptk.many b0 -END(longs_peak_putc) - -/* derived from linux/arch/ia64/hp/sim/boot/boot_head.S */ -GLOBAL_ENTRY(pal_emulator_static) - mov r8=-1 - mov r9=256 - ;; - cmp.gtu p7,p8=r9,r32 /* r32 <= 255? */ -(p7) br.cond.sptk.few static - ;; - mov r9=512 - ;; - cmp.gtu p7,p8=r9,r32 -(p7) br.cond.sptk.few stacked - ;; -static: cmp.eq p7,p8=6,r32 /* PAL_PTCE_INFO */ -(p8) br.cond.sptk.few 1f - ;; - mov r8=0 /* status = 0 */ - movl r9=0x100000000 /* tc.base */ - movl r10=0x0000000200000003 /* count[0], count[1] */ - movl r11=0x1000000000002000 /* stride[0], stride[1] */ - br.ret.sptk.few rp -1: cmp.eq p7,p8=14,r32 /* PAL_FREQ_RATIOS */ -(p8) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9 =0x900000002 /* proc_ratio (1/100) */ - movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ - movl r11=0x900000002 /* itc_ratio<<32 (1/100) */ - ;; -1: cmp.eq p7,p8=19,r32 /* PAL_RSE_INFO */ -(p8) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - mov r9=96 /* num phys stacked */ - mov r10=0 /* hints */ - mov r11=0 - br.ret.sptk.few rp -1: cmp.eq p7,p8=1,r32 /* PAL_CACHE_FLUSH */ -(p8) br.cond.sptk.few 1f -#if 0 - mov r9=ar.lc - movl r8=524288 /* flush 512k million cache lines (16MB) */ - ;; - mov ar.lc=r8 - movl r8=0xe000000000000000 - ;; -.loop: fc r8 - add r8=32,r8 - br.cloop.sptk.few .loop - sync.i - ;; - srlz.i - ;; - mov ar.lc=r9 - mov r8=r0 - ;; -1: cmp.eq p7,p8=15,r32 /* PAL_PERF_MON_INFO */ -(p8) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9 =0x08122f04 /* generic=4 width=47 retired=8 cycles=18 */ - mov r10=0 /* reserved */ - mov r11=0 /* reserved */ - mov r16=0xffff /* implemented PMC */ - mov r17=0x3ffff /* implemented PMD */ - add r18=8,r29 /* second index */ - ;; - st8 [r29]=r16,16 /* store implemented PMC */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r17,16 /* store implemented PMD */ - st8 [r18]=r0,16 /* clear remaining bits */ - mov r16=0xf0 /* cycles count capable PMC */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - mov r17=0xf0 /* retired bundles capable PMC */ - ;; - st8 [r29]=r16,16 /* store cycles capable */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r17,16 /* store retired bundle capable */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; -1: br.cond.sptk.few rp -#else -1: -#endif -stacked: - br.ret.sptk.few rp -END(pal_emulator_static) - -GLOBAL_ENTRY(vhpt_insert) -// alloc loc0 = ar.pfs, 3, 1, 0, 0 - mov r16=r32 - mov r26=r33 - mov r27=r34 - ;; - VHPT_INSERT() -// VHPT_INSERT1() ... add collision chains later -// mov ar.pfs = loc0 - br.ret.sptk.few rp - ;; -END(vhpt_insert) diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xenirq.c --- a/xen/arch/ia64/xenirq.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,77 +0,0 @@ -/* - * Xen irq routines - * - * Copyright (C) 2005 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <asm/ptrace.h> -#include <asm/hw_irq.h> - - -void -xen_debug_irq(ia64_vector vector, struct pt_regs *regs) -{ -//FIXME: For debug only, can be removed - static char firstirq = 1; - static char firsttime[256]; - static char firstpend[256]; - if (firstirq) { - int i; - for (i=0;i<256;i++) firsttime[i] = 1; - for (i=0;i<256;i++) firstpend[i] = 1; - firstirq = 0; - } - if (firsttime[vector]) { - printf("**** (entry) First received int on vector=%d,itc=%lx\n", - (unsigned long) vector, ia64_get_itc()); - firsttime[vector] = 0; - } -} - - -int -xen_do_IRQ(ia64_vector vector) -{ - if (vector != 0xef) { - extern void vcpu_pend_interrupt(void *, int); -#if 0 - if (firsttime[vector]) { - printf("**** (iterate) First received int on vector=%d,itc=%lx\n", - (unsigned long) vector, ia64_get_itc()); - firsttime[vector] = 0; - } - if (firstpend[vector]) { - printf("**** First pended int on vector=%d,itc=%lx\n", - (unsigned long) vector,ia64_get_itc()); - firstpend[vector] = 0; - } -#endif - //FIXME: TEMPORARY HACK!!!! - vcpu_pend_interrupt(dom0->vcpu[0],vector); - vcpu_wake(dom0->vcpu[0]); - return(1); - } - return(0); -} - -/* From linux/kernel/softirq.c */ -#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED -# define invoke_softirq() __do_softirq() -#else -# define invoke_softirq() do_softirq() -#endif - -/* - * Exit an interrupt context. Process softirqs if needed and possible: - */ -void irq_exit(void) -{ - //account_system_vtime(current); - //sub_preempt_count(IRQ_EXIT_OFFSET); - if (!in_interrupt() && local_softirq_pending()) - invoke_softirq(); - //preempt_enable_no_resched(); -} -/* end from linux/kernel/softirq.c */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xenmem.c --- a/xen/arch/ia64/xenmem.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,86 +0,0 @@ -/* - * Xen memory allocator routines - * - * Copyright (C) 2005 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - * Copyright (C) 2005 Intel Corp. - * - * Routines used by ia64 machines with contiguous (or virtually contiguous) - * memory. - */ - -#include <linux/config.h> -#include <asm/pgtable.h> -#include <xen/mm.h> - -extern struct page *zero_page_memmap_ptr; -struct pfn_info *frame_table; -unsigned long frame_table_size; -unsigned long max_page; - -struct page *mem_map; -#define MAX_DMA_ADDRESS ~0UL // FIXME??? - -#ifdef CONFIG_VIRTUAL_MEM_MAP -static unsigned long num_dma_physpages; -#endif - -/* - * Set up the page tables. - */ -#ifdef CONFIG_VTI -unsigned long *mpt_table; -unsigned long mpt_table_size; -#endif // CONFIG_VTI - -void -paging_init (void) -{ - struct pfn_info *pg; - -#ifdef CONFIG_VTI - unsigned int mpt_order; - /* Create machine to physical mapping table - * NOTE: similar to frame table, later we may need virtually - * mapped mpt table if large hole exists. Also MAX_ORDER needs - * to be changed in common code, which only support 16M by far - */ - mpt_table_size = max_page * sizeof(unsigned long); - mpt_order = get_order(mpt_table_size); - ASSERT(mpt_order <= MAX_ORDER); - if ((mpt_table = alloc_xenheap_pages(mpt_order)) == NULL) - panic("Not enough memory to bootstrap Xen.\n"); - - printk("machine to physical table: 0x%lx\n", (u64)mpt_table); - memset(mpt_table, INVALID_M2P_ENTRY, mpt_table_size); -#endif // CONFIG_VTI - - /* Other mapping setup */ - - zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); -} - -/* FIXME: postpone support to machines with big holes between physical memorys. - * Current hack allows only efi memdesc upto 4G place. (See efi.c) - */ -#ifndef CONFIG_VIRTUAL_MEM_MAP -#define FT_ALIGN_SIZE (16UL << 20) -void __init init_frametable(void) -{ - unsigned long i, pfn; - frame_table_size = max_page * sizeof(struct pfn_info); - frame_table_size = (frame_table_size + PAGE_SIZE - 1) & PAGE_MASK; - - /* Request continuous trunk from boot allocator, since HV - * address is identity mapped */ - pfn = alloc_boot_pages( - frame_table_size >> PAGE_SHIFT, FT_ALIGN_SIZE >> PAGE_SHIFT); - if (pfn == 0) - panic("Not enough memory for frame table.\n"); - - frame_table = __va(pfn << PAGE_SHIFT); - memset(frame_table, 0, frame_table_size); - printk("size of frame_table: %lukB\n", - frame_table_size >> 10); -} -#endif diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xenmisc.c --- a/xen/arch/ia64/xenmisc.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,391 +0,0 @@ -/* - * Xen misc - * - * Functions/decls that are/may be needed to link with Xen because - * of x86 dependencies - * - * Copyright (C) 2004 Hewlett-Packard Co. - * Dan Magenheimer (dan.magenheimer@xxxxxx) - * - */ - -#include <linux/config.h> -#include <xen/sched.h> -#include <linux/efi.h> -#include <asm/processor.h> -#include <xen/serial.h> -#include <asm/io.h> -#include <xen/softirq.h> - -efi_memory_desc_t ia64_efi_io_md; -EXPORT_SYMBOL(ia64_efi_io_md); -unsigned long wait_init_idle; -int phys_proc_id[NR_CPUS]; -unsigned long loops_per_jiffy = (1<<12); // from linux/init/main.c - -void unw_init(void) { printf("unw_init() skipped (NEED FOR KERNEL UNWIND)\n"); } -void ia64_mca_init(void) { printf("ia64_mca_init() skipped (Machine check abort handling)\n"); } -void ia64_mca_cpu_init(void *x) { } -void ia64_patch_mckinley_e9(unsigned long a, unsigned long b) { } -void ia64_patch_vtop(unsigned long a, unsigned long b) { } -void hpsim_setup(char **x) -{ -#ifdef CONFIG_SMP - init_smp_config(); -#endif -} - -// called from mem_init... don't think s/w I/O tlb is needed in Xen -//void swiotlb_init(void) { } ...looks like it IS needed - -long -is_platform_hp_ski(void) -{ - int i; - long cpuid[6]; - - for (i = 0; i < 5; ++i) - cpuid[i] = ia64_get_cpuid(i); - if ((cpuid[0] & 0xff) != 'H') return 0; - if ((cpuid[3] & 0xff) != 0x4) return 0; - if (((cpuid[3] >> 8) & 0xff) != 0x0) return 0; - if (((cpuid[3] >> 16) & 0xff) != 0x0) return 0; - if (((cpuid[3] >> 24) & 0x7) != 0x7) return 0; - return 1; -} - -long -platform_is_hp_ski(void) -{ - extern long running_on_sim; - return running_on_sim; -} - -/* calls in xen/common code that are unused on ia64 */ - -void sync_lazy_execstate_cpu(unsigned int cpu) {} - -#ifdef CONFIG_VTI -int grant_table_create(struct domain *d) { return 0; } -void grant_table_destroy(struct domain *d) { return; } -#endif - -struct pt_regs *guest_cpu_user_regs(void) { return ia64_task_regs(current); } - -void raise_actimer_softirq(void) -{ - raise_softirq(AC_TIMER_SOFTIRQ); -} - -#ifndef CONFIG_VTI -unsigned long -__gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) -{ - if (d == dom0) - return(gpfn); - else { - unsigned long pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT); - if (!pte) { -printk("__gpfn_to_mfn_foreign: bad gpfn. spinning...\n"); -while(1); - return 0; - } - return ((pte & _PFN_MASK) >> PAGE_SHIFT); - } -} - -u32 -__mfn_to_gpfn(struct domain *d, unsigned long frame) -{ - // FIXME: is this right? -if ((frame << PAGE_SHIFT) & _PAGE_PPN_MASK) { -printk("__mfn_to_gpfn: bad frame. spinning...\n"); -while(1); -} - return frame; -} -#endif - -#ifndef CONFIG_VTI -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...) -{ - printf("__hypercall_create_continuation: not implemented!!!\n"); -} -#endif - -/////////////////////////////// - -/////////////////////////////// -// from arch/x86/apic.c -/////////////////////////////// - -extern unsigned long domain0_ready; - -int reprogram_ac_timer(s_time_t timeout) -{ - struct vcpu *v = current; - -#ifdef CONFIG_VTI -// if(VMX_DOMAIN(v)) - return 1; -#endif // CONFIG_VTI - if (!domain0_ready) return 1; - local_cpu_data->itm_next = timeout; - if (is_idle_task(v->domain)) vcpu_safe_set_itm(timeout); - else vcpu_set_next_timer(current); - return 1; -} - -/////////////////////////////// -// from arch/ia64/page_alloc.c -/////////////////////////////// -DEFINE_PER_CPU(struct page_state, page_states) = {0}; -unsigned long totalram_pages; - -void __mod_page_state(unsigned offset, unsigned long delta) -{ - unsigned long flags; - void* ptr; - - local_irq_save(flags); - ptr = &__get_cpu_var(page_states); - *(unsigned long*)(ptr + offset) += delta; - local_irq_restore(flags); -} - -/////////////////////////////// -// from arch/x86/flushtlb.c -/////////////////////////////// - -u32 tlbflush_clock; -u32 tlbflush_time[NR_CPUS]; - -/////////////////////////////// -// from arch/x86/memory.c -/////////////////////////////// - -void init_percpu_info(void) -{ - dummy(); - //memset(percpu_info, 0, sizeof(percpu_info)); -} - -void free_page_type(struct pfn_info *page, unsigned int type) -{ - dummy(); -} - -/////////////////////////////// -//// misc memory stuff -/////////////////////////////// - -unsigned long __get_free_pages(unsigned int mask, unsigned int order) -{ - void *p = alloc_xenheap_pages(order); - - memset(p,0,PAGE_SIZE<<order); - return (unsigned long)p; -} - -void __free_pages(struct page *page, unsigned int order) -{ - if (order) BUG(); - free_xenheap_page(page); -} - -void *pgtable_quicklist_alloc(void) -{ - return alloc_xenheap_pages(0); -} - -void pgtable_quicklist_free(void *pgtable_entry) -{ - free_xenheap_page(pgtable_entry); -} - -/////////////////////////////// -// from arch/ia64/traps.c -/////////////////////////////// - -void show_registers(struct pt_regs *regs) -{ - printf("*** ADD REGISTER DUMP HERE FOR DEBUGGING\n"); -} - -int is_kernel_text(unsigned long addr) -{ - extern char _stext[], _etext[]; - if (addr >= (unsigned long) _stext && - addr <= (unsigned long) _etext) - return 1; - - return 0; -} - -unsigned long kernel_text_end(void) -{ - extern char _etext[]; - return (unsigned long) _etext; -} - -/////////////////////////////// -// from common/keyhandler.c -/////////////////////////////// -void dump_pageframe_info(struct domain *d) -{ - printk("dump_pageframe_info not implemented\n"); -} - -/////////////////////////////// -// called from arch/ia64/head.S -/////////////////////////////// - -void console_print(char *msg) -{ - printk("console_print called, how did start_kernel return???\n"); -} - -void kernel_thread_helper(void) -{ - printk("kernel_thread_helper not implemented\n"); - dummy(); -} - -void sys_exit(void) -{ - printk("sys_exit not implemented\n"); - dummy(); -} - -//////////////////////////////////// -// called from unaligned.c -//////////////////////////////////// - -void die_if_kernel(char *str, struct pt_regs *regs, long err) /* __attribute__ ((noreturn)) */ -{ - printk("die_if_kernel: called, not implemented\n"); -} - -long -ia64_peek (struct task_struct *child, struct switch_stack *child_stack, - unsigned long user_rbs_end, unsigned long addr, long *val) -{ - printk("ia64_peek: called, not implemented\n"); -} - -long -ia64_poke (struct task_struct *child, struct switch_stack *child_stack, - unsigned long user_rbs_end, unsigned long addr, long val) -{ - printk("ia64_poke: called, not implemented\n"); -} - -void -ia64_sync_fph (struct task_struct *task) -{ - printk("ia64_sync_fph: called, not implemented\n"); -} - -void -ia64_flush_fph (struct task_struct *task) -{ - printk("ia64_flush_fph: called, not implemented\n"); -} - -//////////////////////////////////// -// called from irq_ia64.c:init_IRQ() -// (because CONFIG_IA64_HP_SIM is specified) -//////////////////////////////////// -void hpsim_irq_init(void) { } - - -// accomodate linux extable.c -//const struct exception_table_entry * -void *search_module_extables(unsigned long addr) { return NULL; } -void *__module_text_address(unsigned long addr) { return NULL; } -void *module_text_address(unsigned long addr) { return NULL; } - -void cs10foo(void) {} -void cs01foo(void) {} - -unsigned long context_switch_count = 0; - -void context_switch(struct vcpu *prev, struct vcpu *next) -{ -//printk("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); -//printk("@@@@@@ context switch from domain %d (%x) to domain %d (%x)\n", -//prev->domain->domain_id,(long)prev&0xffffff,next->domain->domain_id,(long)next&0xffffff); -//if (prev->domain->domain_id == 1 && next->domain->domain_id == 0) cs10foo(); -//if (prev->domain->domain_id == 0 && next->domain->domain_id == 1) cs01foo(); -//printk("@@sw %d->%d\n",prev->domain->domain_id,next->domain->domain_id); -#ifdef CONFIG_VTI - vtm_domain_out(prev); -#endif - context_switch_count++; - switch_to(prev,next,prev); -#ifdef CONFIG_VTI - vtm_domain_in(current); -#endif - -// leave this debug for now: it acts as a heartbeat when more than -// one domain is active -{ -static long cnt[16] = { 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50}; -static int i = 100; -int id = ((struct vcpu *)current)->domain->domain_id & 0xf; -if (!cnt[id]--) { printk("%x",id); cnt[id] = 500000; } -if (!i--) { printk("+",id); i = 1000000; } -} - -#ifdef CONFIG_VTI - if (VMX_DOMAIN(current)) - vmx_load_all_rr(current); -#else - if (!is_idle_task(current->domain)) { - load_region_regs(current); - if (vcpu_timer_expired(current)) vcpu_pend_timer(current); - } - if (vcpu_timer_expired(current)) vcpu_pend_timer(current); -#endif -} - -void context_switch_finalise(struct vcpu *next) -{ - /* nothing to do */ -} - -void continue_running(struct vcpu *same) -{ - /* nothing to do */ -} - -void panic_domain(struct pt_regs *regs, const char *fmt, ...) -{ - va_list args; - char buf[128]; - struct vcpu *v = current; - static volatile int test = 1; // so can continue easily in debug - extern spinlock_t console_lock; - unsigned long flags; - -loop: - printf("$$$$$ PANIC in domain %d (k6=%p): ", - v->domain->domain_id, - __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT]); - va_start(args, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - printf(buf); - if (regs) show_registers(regs); - domain_pause_by_systemcontroller(current->domain); - v->domain->shutdown_code = SHUTDOWN_crash; - set_bit(_DOMF_shutdown, v->domain->domain_flags); - if (v->domain->domain_id == 0) { - int i = 1000000000L; - // if domain0 crashes, just periodically print out panic - // message to make post-mortem easier - while(i--); - goto loop; - } -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xensetup.c --- a/xen/arch/ia64/xensetup.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,389 +0,0 @@ -/****************************************************************************** - * xensetup.c - * Copyright (c) 2004-2005 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/errno.h> -//#include <xen/spinlock.h> -#include <xen/multiboot.h> -#include <xen/sched.h> -#include <xen/mm.h> -//#include <xen/delay.h> -#include <xen/compile.h> -//#include <xen/console.h> -#include <xen/serial.h> -#include <xen/trace.h> -#include <asm/meminit.h> -#include <asm/page.h> -#include <asm/setup.h> -#include <xen/string.h> - -unsigned long xenheap_phys_end; - -char saved_command_line[COMMAND_LINE_SIZE]; - -struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu }; - -cpumask_t cpu_present_map; - -#ifdef CLONE_DOMAIN0 -struct domain *clones[CLONE_DOMAIN0]; -#endif -extern unsigned long domain0_ready; - -int find_max_pfn (unsigned long, unsigned long, void *); -void start_of_day(void); - -/* opt_nosmp: If true, secondary processors are ignored. */ -static int opt_nosmp = 0; -boolean_param("nosmp", opt_nosmp); - -/* maxcpus: maximum number of CPUs to activate. */ -static unsigned int max_cpus = NR_CPUS; -integer_param("maxcpus", max_cpus); - -/* - * opt_xenheap_megabytes: Size of Xen heap in megabytes, including: - * xen image - * bootmap bits - * xen heap - * Note: To allow xenheap size configurable, the prerequisite is - * to configure elilo allowing relocation defaultly. Then since - * elilo chooses 256M as alignment when relocating, alignment issue - * on IPF can be addressed. - */ -unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB; -unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE; -extern long running_on_sim; -unsigned long xen_pstart; - -static int -xen_count_pages(u64 start, u64 end, void *arg) -{ - unsigned long *count = arg; - - /* FIXME: do we need consider difference between DMA-usable memory and - * normal memory? Seems that HV has no requirement to operate DMA which - * is owned by Dom0? */ - *count += (end - start) >> PAGE_SHIFT; - return 0; -} - -/* Find first hole after trunk for xen image */ -static int -xen_find_first_hole(u64 start, u64 end, void *arg) -{ - unsigned long *first_hole = arg; - - if ((*first_hole) == 0) { - if ((start <= KERNEL_START) && (KERNEL_START < end)) - *first_hole = __pa(end); - } - - return 0; -} - -static void __init do_initcalls(void) -{ - initcall_t *call; - for ( call = &__initcall_start; call < &__initcall_end; call++ ) - (*call)(); -} - -/* - * IPF loader only supports one commaind line currently, for - * both xen and guest kernel. This function provides pre-parse - * to mixed command line, to split it into two parts. - * - * User should split the parameters by "--", with strings after - * spliter for guest kernel. Missing "--" means whole line belongs - * to guest. Example: - * "com2=57600,8n1 console=com2 -- console=ttyS1 console=tty - * root=/dev/sda3 ro" - */ -static char null[4] = { 0 }; - -void early_cmdline_parse(char **cmdline_p) -{ - char *guest_cmd; - char *split = "--"; - - if (*cmdline_p == NULL) { - *cmdline_p = &null[0]; - saved_command_line[0] = '\0'; - return; - } - - guest_cmd = strstr(*cmdline_p, split); - /* If no spliter, whole line is for guest */ - if (guest_cmd == NULL) { - guest_cmd = *cmdline_p; - *cmdline_p = &null[0]; - } else { - *guest_cmd = '\0'; /* Split boot parameters for xen and guest */ - guest_cmd += strlen(split); - while (*guest_cmd == ' ') guest_cmd++; - } - - strlcpy(saved_command_line, guest_cmd, COMMAND_LINE_SIZE); - return; -} - -struct ns16550_defaults ns16550_com1 = { - .baud = BAUD_AUTO, - .data_bits = 8, - .parity = 'n', - .stop_bits = 1 -}; - -struct ns16550_defaults ns16550_com2 = { - .baud = BAUD_AUTO, - .data_bits = 8, - .parity = 'n', - .stop_bits = 1 -}; - -void start_kernel(void) -{ - unsigned char *cmdline; - void *heap_start; - int i; - unsigned long max_mem, nr_pages, firsthole_start; - unsigned long dom0_memory_start, dom0_memory_end; - unsigned long initial_images_start, initial_images_end; - - running_on_sim = is_platform_hp_ski(); - /* Kernel may be relocated by EFI loader */ - xen_pstart = ia64_tpa(KERNEL_START); - - /* Must do this early -- e.g., spinlocks rely on get_current(). */ - //set_current(&idle0_vcpu); - ia64_r13 = (void *)&idle0_vcpu; - idle0_vcpu.domain = &idle0_domain; - - early_setup_arch(&cmdline); - - /* We initialise the serial devices very early so we can get debugging. */ - if (running_on_sim) hpsim_serial_init(); - else { - ns16550_init(0, &ns16550_com1); - /* Also init com2 for Tiger4. */ - ns16550_com2.io_base = 0x2f8; - ns16550_com2.irq = 3; - ns16550_init(1, &ns16550_com2); - } - serial_init_preirq(); - - init_console(); - set_printk_prefix("(XEN) "); - - /* xenheap should be in same TR-covered range with xen image */ - xenheap_phys_end = xen_pstart + xenheap_size; - printk("xen image pstart: 0x%lx, xenheap pend: 0x%lx\n", - xen_pstart, xenheap_phys_end); - - /* Find next hole */ - firsthole_start = 0; - efi_memmap_walk(xen_find_first_hole, &firsthole_start); - - initial_images_start = xenheap_phys_end; - initial_images_end = initial_images_start + ia64_boot_param->initrd_size; - - /* Later may find another memory trunk, even away from xen image... */ - if (initial_images_end > firsthole_start) { - printk("Not enough memory to stash the DOM0 kernel image.\n"); - printk("First hole:0x%lx, relocation end: 0x%lx\n", - firsthole_start, initial_images_end); - for ( ; ; ); - } - - /* This copy is time consuming, but elilo may load Dom0 image - * within xenheap range */ - printk("ready to move Dom0 to 0x%lx...", initial_images_start); - memmove(__va(initial_images_start), - __va(ia64_boot_param->initrd_start), - ia64_boot_param->initrd_size); - ia64_boot_param->initrd_start = initial_images_start; - printk("Done\n"); - - /* first find highest page frame number */ - max_page = 0; - efi_memmap_walk(find_max_pfn, &max_page); - printf("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page); - - heap_start = memguard_init(ia64_imva(&_end)); - printf("Before heap_start: 0x%lx\n", heap_start); - heap_start = __va(init_boot_allocator(__pa(heap_start))); - printf("After heap_start: 0x%lx\n", heap_start); - - reserve_memory(); - - efi_memmap_walk(filter_rsvd_memory, init_boot_pages); - efi_memmap_walk(xen_count_pages, &nr_pages); - - printk("System RAM: %luMB (%lukB)\n", - nr_pages >> (20 - PAGE_SHIFT), - nr_pages << (PAGE_SHIFT - 10)); - - init_frametable(); - - ia64_fph_enable(); - __ia64_init_fpu(); - - alloc_dom0(); -#ifdef DOMU_BUILD_STAGING - alloc_domU_staging(); -#endif - - end_boot_allocator(); - - init_xenheap_pages(__pa(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); - - late_setup_arch(&cmdline); - setup_per_cpu_areas(); - mem_init(); - -printk("About to call scheduler_init()\n"); - scheduler_init(); - local_irq_disable(); -printk("About to call xen_time_init()\n"); - xen_time_init(); -#ifdef CONFIG_VTI - init_xen_time(); /* initialise the time */ -#endif // CONFIG_VTI -printk("About to call ac_timer_init()\n"); - ac_timer_init(); -// init_xen_time(); ??? - -#ifdef CONFIG_SMP - if ( opt_nosmp ) - { - max_cpus = 0; - smp_num_siblings = 1; - //boot_cpu_data.x86_num_cores = 1; - } - - smp_prepare_cpus(max_cpus); - - /* We aren't hotplug-capable yet. */ - //BUG_ON(!cpus_empty(cpu_present_map)); - for_each_cpu ( i ) - cpu_set(i, cpu_present_map); - - //BUG_ON(!local_irq_is_enabled()); - -printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); - for_each_present_cpu ( i ) - { - if ( num_online_cpus() >= max_cpus ) - break; - if ( !cpu_online(i) ) { -printk("About to call __cpu_up(%d)\n",i); - __cpu_up(i); - } - } - - printk("Brought up %ld CPUs\n", (long)num_online_cpus()); - smp_cpus_done(max_cpus); -#endif - - - // FIXME: Should the following be swapped and moved later? - schedulers_start(); - do_initcalls(); -printk("About to call sort_main_extable()\n"); - sort_main_extable(); - - /* surrender usage of kernel registers to domain, use percpu area instead */ - __get_cpu_var(cpu_kr)._kr[IA64_KR_IO_BASE] = ia64_get_kr(IA64_KR_IO_BASE); - __get_cpu_var(cpu_kr)._kr[IA64_KR_PER_CPU_DATA] = ia64_get_kr(IA64_KR_PER_CPU_DATA); - __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT_STACK] = ia64_get_kr(IA64_KR_CURRENT_STACK); - __get_cpu_var(cpu_kr)._kr[IA64_KR_FPU_OWNER] = ia64_get_kr(IA64_KR_FPU_OWNER); - __get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT] = ia64_get_kr(IA64_KR_CURRENT); - __get_cpu_var(cpu_kr)._kr[IA64_KR_PT_BASE] = ia64_get_kr(IA64_KR_PT_BASE); - - /* Create initial domain 0. */ -printk("About to call do_createdomain()\n"); - dom0 = do_createdomain(0, 0); - init_task.domain = &idle0_domain; - init_task.processor = 0; -// init_task.mm = &init_mm; - init_task.domain->arch.mm = &init_mm; -// init_task.thread = INIT_THREAD; - //arch_do_createdomain(current); -#ifdef CLONE_DOMAIN0 - { - int i; - for (i = 0; i < CLONE_DOMAIN0; i++) { - clones[i] = do_createdomain(i+1, 0); - if ( clones[i] == NULL ) - panic("Error creating domain0 clone %d\n",i); - } - } -#endif - if ( dom0 == NULL ) - panic("Error creating domain 0\n"); - - set_bit(_DOMF_privileged, &dom0->domain_flags); - - /* - * We're going to setup domain0 using the module(s) that we stashed safely - * above our heap. The second module, if present, is an initrd ramdisk. - */ -printk("About to call construct_dom0()\n"); - dom0_memory_start = __va(ia64_boot_param->initrd_start); - dom0_memory_end = ia64_boot_param->initrd_size; - if ( construct_dom0(dom0, dom0_memory_start, dom0_memory_end, - 0, - 0, - 0) != 0) - panic("Could not set up DOM0 guest OS\n"); -#ifdef CLONE_DOMAIN0 - { - int i; - dom0_memory_start = __va(ia64_boot_param->initrd_start); - dom0_memory_end = ia64_boot_param->initrd_size; - for (i = 0; i < CLONE_DOMAIN0; i++) { -printk("CONSTRUCTING DOMAIN0 CLONE #%d\n",i+1); - if ( construct_domU(clones[i], dom0_memory_start, dom0_memory_end, - 0, - 0, - 0) != 0) - panic("Could not set up DOM0 clone %d\n",i); - } - } -#endif - - /* The stash space for the initial kernel image can now be freed up. */ - init_domheap_pages(ia64_boot_param->initrd_start, - ia64_boot_param->initrd_start + ia64_boot_param->initrd_size); - if (!running_on_sim) // slow on ski and pages are pre-initialized to zero - scrub_heap_pages(); - -printk("About to call init_trace_bufs()\n"); - init_trace_bufs(); - - /* Give up the VGA console if DOM0 is configured to grab it. */ -#ifndef IA64 - console_endboot(cmdline && strstr(cmdline, "tty0")); -#endif - -#ifdef CLONE_DOMAIN0 - { - int i; - for (i = 0; i < CLONE_DOMAIN0; i++) - domain_unpause_by_systemcontroller(clones[i]); - } -#endif - domain_unpause_by_systemcontroller(dom0); - domain0_ready = 1; - local_irq_enable(); -printk("About to call startup_cpu_idle_loop()\n"); - startup_cpu_idle_loop(); -} diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/arch/ia64/xentime.c --- a/xen/arch/ia64/xentime.c Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,382 +0,0 @@ -/* - * xen/arch/ia64/time.c - * - * Copyright (C) 2005 Hewlett-Packard Co - * Dan Magenheimer <dan.magenheimer@xxxxxx> - */ - -#include <linux/config.h> - -#include <linux/cpu.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/profile.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/interrupt.h> -#include <linux/efi.h> -#include <linux/profile.h> -#include <linux/timex.h> - -#include <asm/machvec.h> -#include <asm/delay.h> -#include <asm/hw_irq.h> -#include <asm/ptrace.h> -#include <asm/sal.h> -#include <asm/sections.h> -#include <asm/system.h> -#ifdef XEN -#include <asm/vcpu.h> -#include <linux/jiffies.h> // not included by xen/sched.h -#endif -#include <xen/softirq.h> - -#ifdef XEN -seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; -#endif - -#define TIME_KEEPER_ID 0 -extern unsigned long wall_jiffies; - -static s_time_t stime_irq; /* System time at last 'time update' */ - -unsigned long domain0_ready = 0; - -#ifndef CONFIG_VTI -static inline u64 get_time_delta(void) -{ - return ia64_get_itc(); -} -#else // CONFIG_VTI -static s_time_t stime_irq = 0x0; /* System time at last 'time update' */ -unsigned long itc_scale; -unsigned long itc_at_irq; -static unsigned long wc_sec, wc_nsec; /* UTC time at last 'time update'. */ -//static rwlock_t time_lock = RW_LOCK_UNLOCKED; -static irqreturn_t vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs); - -static inline u64 get_time_delta(void) -{ - s64 delta_itc; - u64 delta, cur_itc; - - cur_itc = ia64_get_itc(); - - delta_itc = (s64)(cur_itc - itc_at_irq); - if ( unlikely(delta_itc < 0) ) delta_itc = 0; - delta = ((u64)delta_itc) * itc_scale; - delta = delta >> 32; - - return delta; -} - -u64 tick_to_ns(u64 tick) -{ - return (tick * itc_scale) >> 32; -} -#endif // CONFIG_VTI - -s_time_t get_s_time(void) -{ - s_time_t now; - unsigned long flags; - - read_lock_irqsave(&xtime_lock, flags); - - now = stime_irq + get_time_delta(); - - /* Ensure that the returned system time is monotonically increasing. */ - { - static s_time_t prev_now = 0; - if ( unlikely(now < prev_now) ) - now = prev_now; - prev_now = now; - } - - read_unlock_irqrestore(&xtime_lock, flags); - - return now; -} - -void update_dom_time(struct vcpu *v) -{ -// FIXME: implement this? -// printf("update_dom_time: called, not implemented, skipping\n"); - return; -} - -/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */ -void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) -{ -#ifdef CONFIG_VTI - u64 _nsecs; - - write_lock_irq(&xtime_lock); - - _nsecs = (u64)nsecs + (s64)(stime_irq - system_time_base); - while ( _nsecs >= 1000000000 ) - { - _nsecs -= 1000000000; - secs++; - } - - wc_sec = secs; - wc_nsec = (unsigned long)_nsecs; - - write_unlock_irq(&xtime_lock); - - update_dom_time(current->domain); -#else -// FIXME: Should this be do_settimeofday (from linux)??? - printf("do_settime: called, not implemented, stopping\n"); - dummy(); -#endif -} - -irqreturn_t -xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long new_itm; - -#define HEARTBEAT_FREQ 16 // period in seconds -#ifdef HEARTBEAT_FREQ - static long count = 0; - if (!(++count & ((HEARTBEAT_FREQ*1024)-1))) { - printf("Heartbeat... iip=%p,psr.i=%d,pend=%d\n", - regs->cr_iip, - VCPU(current,interrupt_delivery_enabled), - VCPU(current,pending_interruption)); - count = 0; - } -#endif -#ifndef XEN - if (unlikely(cpu_is_offline(smp_processor_id()))) { - return IRQ_HANDLED; - } -#endif -#ifdef XEN - if (current->domain == dom0) { - // FIXME: there's gotta be a better way of doing this... - // We have to ensure that domain0 is launched before we - // call vcpu_timer_expired on it - //domain0_ready = 1; // moved to xensetup.c - VCPU(current,pending_interruption) = 1; - } - if (domain0_ready && vcpu_timer_expired(dom0->vcpu[0])) { - vcpu_pend_timer(dom0->vcpu[0]); - //vcpu_set_next_timer(dom0->vcpu[0]); - vcpu_wake(dom0->vcpu[0]); - } - if (!is_idle_task(current->domain) && current->domain != dom0) { - if (vcpu_timer_expired(current)) { - vcpu_pend_timer(current); - // ensure another timer interrupt happens even if domain doesn't - vcpu_set_next_timer(current); - vcpu_wake(current); - } - } - raise_actimer_softirq(); -#endif - -#ifndef XEN - platform_timer_interrupt(irq, dev_id, regs); -#endif - - new_itm = local_cpu_data->itm_next; - - if (!time_after(ia64_get_itc(), new_itm)) -#ifdef XEN - return; -#else - printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", - ia64_get_itc(), new_itm); -#endif - -#ifdef XEN -// printf("GOT TO HERE!!!!!!!!!!!\n"); - //while(1); -#else - profile_tick(CPU_PROFILING, regs); -#endif - - while (1) { -#ifndef XEN - update_process_times(user_mode(regs)); -#endif - - new_itm += local_cpu_data->itm_delta; - - if (smp_processor_id() == TIME_KEEPER_ID) { - /* - * Here we are in the timer irq handler. We have irqs locally - * disabled, but we don't know if the timer_bh is running on - * 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; -#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; - } - - do { - /* - * If we're too close to the next clock tick for - * comfort, we increase the safety margin by - * intentionally dropping the next tick(s). We do NOT - * update itm.next because that would force us to call - * do_timer() which in turn would let our clock run - * too fast (with the potentially devastating effect - * of losing monotony of time). - */ - while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) - new_itm += local_cpu_data->itm_delta; -//#ifdef XEN -// vcpu_set_next_timer(current); -//#else -//printf("***** timer_interrupt: Setting itm to %lx\n",new_itm); - ia64_set_itm(new_itm); -//#endif - /* double check, in case we got hit by a (slow) PMI: */ - } while (time_after_eq(ia64_get_itc(), new_itm)); - return IRQ_HANDLED; -} - -static struct irqaction xen_timer_irqaction = { -#ifdef CONFIG_VTI - .handler = vmx_timer_interrupt, -#else // CONFIG_VTI - .handler = xen_timer_interrupt, -#endif // CONFIG_VTI -#ifndef XEN - .flags = SA_INTERRUPT, -#endif - .name = "timer" -}; - -void __init -xen_time_init (void) -{ - register_percpu_irq(IA64_TIMER_VECTOR, &xen_timer_irqaction); - ia64_init_itm(); -} - - -#ifdef CONFIG_VTI - -/* Late init function (after all CPUs are booted). */ -int __init init_xen_time() -{ - struct timespec tm; - - itc_scale = 1000000000UL << 32 ; - itc_scale /= local_cpu_data->itc_freq; - - /* System time ticks from zero. */ - stime_irq = (s_time_t)0; - itc_at_irq = ia64_get_itc(); - - /* Wallclock time starts as the initial RTC time. */ - efi_gettimeofday(&tm); - wc_sec = tm.tv_sec; - wc_nsec = tm.tv_nsec; - - - printk("Time init:\n"); - printk(".... System Time: %ldns\n", NOW()); - printk(".... scale: %16lX\n", itc_scale); - printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_nsec/1000); - - return 0; -} - -static irqreturn_t -vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long new_itm; - struct vcpu *v = current; - - - new_itm = local_cpu_data->itm_next; - - if (!time_after(ia64_get_itc(), new_itm)) - return; - - while (1) { -#ifdef CONFIG_SMP - /* - * For UP, this is done in do_timer(). Weird, but - * fixing that would require updates to all - * platforms. - */ - update_process_times(user_mode(v, regs)); -#endif - new_itm += local_cpu_data->itm_delta; - - if (smp_processor_id() == TIME_KEEPER_ID) { - /* - * Here we are in the timer irq handler. We have irqs locally - * disabled, but we don't know if the timer_bh is running on - * another CPU. We need to avoid to SMP race by acquiring the - * xtime_lock. - */ - local_cpu_data->itm_next = new_itm; - - write_lock_irq(&xtime_lock); - /* Update jiffies counter. */ - (*(unsigned long *)&jiffies_64)++; - - /* Update wall time. */ - wc_nsec += 1000000000/HZ; - if ( wc_nsec >= 1000000000 ) - { - wc_nsec -= 1000000000; - wc_sec++; - } - - /* Updates system time (nanoseconds since boot). */ - stime_irq += MILLISECS(1000/HZ); - itc_at_irq = ia64_get_itc(); - - write_unlock_irq(&xtime_lock); - - } else - local_cpu_data->itm_next = new_itm; - - if (time_after(new_itm, ia64_get_itc())) - break; - } - - do { - /* - * If we're too close to the next clock tick for - * comfort, we increase the safety margin by - * intentionally dropping the next tick(s). We do NOT - * update itm.next because that would force us to call - * do_timer() which in turn would let our clock run - * too fast (with the potentially devastating effect - * of losing monotony of time). - */ - while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) - new_itm += local_cpu_data->itm_delta; - ia64_set_itm(new_itm); - /* double check, in case we got hit by a (slow) PMI: */ - } while (time_after_eq(ia64_get_itc(), new_itm)); - raise_softirq(AC_TIMER_SOFTIRQ); - - return IRQ_HANDLED; -} -#endif // CONFIG_VTI - diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/asm/pgtable.h --- a/xen/include/asm-ia64/linux/asm/pgtable.h Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,567 +0,0 @@ -#ifndef _ASM_IA64_PGTABLE_H -#define _ASM_IA64_PGTABLE_H - -/* - * This file contains the functions and defines necessary to modify and use - * the IA-64 page table tree. - * - * This hopefully works with any (fixed) IA-64 page-size, as defined - * in <asm/page.h>. - * - * Copyright (C) 1998-2004 Hewlett-Packard Co - * David Mosberger-Tang <davidm@xxxxxxxxxx> - */ - -#include <linux/config.h> - -#include <asm/mman.h> -#include <asm/page.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/types.h> - -#define IA64_MAX_PHYS_BITS 50 /* max. number of physical address bits (architected) */ - -/* - * First, define the various bits in a PTE. Note that the PTE format - * matches the VHPT short format, the firt doubleword of the VHPD long - * format, and the first doubleword of the TLB insertion format. - */ -#define _PAGE_P_BIT 0 -#define _PAGE_A_BIT 5 -#define _PAGE_D_BIT 6 - -#define _PAGE_P (1 << _PAGE_P_BIT) /* page present bit */ -#define _PAGE_MA_WB (0x0 << 2) /* write back memory attribute */ -#define _PAGE_MA_UC (0x4 << 2) /* uncacheable memory attribute */ -#define _PAGE_MA_UCE (0x5 << 2) /* UC exported attribute */ -#define _PAGE_MA_WC (0x6 << 2) /* write coalescing memory attribute */ -#define _PAGE_MA_NAT (0x7 << 2) /* not-a-thing attribute */ -#define _PAGE_MA_MASK (0x7 << 2) -#define _PAGE_PL_0 (0 << 7) /* privilege level 0 (kernel) */ -#define _PAGE_PL_1 (1 << 7) /* privilege level 1 (unused) */ -#define _PAGE_PL_2 (2 << 7) /* privilege level 2 (unused) */ -#define _PAGE_PL_3 (3 << 7) /* privilege level 3 (user) */ -#define _PAGE_PL_MASK (3 << 7) -#define _PAGE_AR_R (0 << 9) /* read only */ -#define _PAGE_AR_RX (1 << 9) /* read & execute */ -#define _PAGE_AR_RW (2 << 9) /* read & write */ -#define _PAGE_AR_RWX (3 << 9) /* read, write & execute */ -#define _PAGE_AR_R_RW (4 << 9) /* read / read & write */ -#define _PAGE_AR_RX_RWX (5 << 9) /* read & exec / read, write & exec */ -#define _PAGE_AR_RWX_RW (6 << 9) /* read, write & exec / read & write */ -#define _PAGE_AR_X_RX (7 << 9) /* exec & promote / read & exec */ -#define _PAGE_AR_MASK (7 << 9) -#define _PAGE_AR_SHIFT 9 -#define _PAGE_A (1 << _PAGE_A_BIT) /* page accessed bit */ -#define _PAGE_D (1 << _PAGE_D_BIT) /* page dirty bit */ -#define _PAGE_PPN_MASK (((__IA64_UL(1) << IA64_MAX_PHYS_BITS) - 1) & ~0xfffUL) -#define _PAGE_ED (__IA64_UL(1) << 52) /* exception deferral */ -#define _PAGE_PROTNONE (__IA64_UL(1) << 63) - -/* Valid only for a PTE with the present bit cleared: */ -#define _PAGE_FILE (1 << 1) /* see swap & file pte remarks below */ - -#define _PFN_MASK _PAGE_PPN_MASK -/* Mask of bits which may be changed by pte_modify(); the odd bits are there for _PAGE_PROTNONE */ -#define _PAGE_CHG_MASK (_PAGE_P | _PAGE_PROTNONE | _PAGE_PL_MASK | _PAGE_AR_MASK | _PAGE_ED) - -#define _PAGE_SIZE_4K 12 -#define _PAGE_SIZE_8K 13 -#define _PAGE_SIZE_16K 14 -#define _PAGE_SIZE_64K 16 -#define _PAGE_SIZE_256K 18 -#define _PAGE_SIZE_1M 20 -#define _PAGE_SIZE_4M 22 -#define _PAGE_SIZE_16M 24 -#define _PAGE_SIZE_64M 26 -#define _PAGE_SIZE_256M 28 -#define _PAGE_SIZE_1G 30 -#define _PAGE_SIZE_4G 32 - -#define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB -#define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB -#define __DIRTY_BITS _PAGE_ED | __DIRTY_BITS_NO_ED - -/* - * Definitions for first level: - * - * PGDIR_SHIFT determines what a first-level page table entry can map. - */ -#define PGDIR_SHIFT (PAGE_SHIFT + 2*(PAGE_SHIFT-3)) -#define PGDIR_SIZE (__IA64_UL(1) << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PTRS_PER_PGD (1UL << (PAGE_SHIFT-3)) -#define USER_PTRS_PER_PGD (5*PTRS_PER_PGD/8) /* regions 0-4 are user regions */ -#define FIRST_USER_PGD_NR 0 - -/* - * Definitions for second level: - * - * PMD_SHIFT determines the size of the area a second-level page table - * can map. - */ -#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) -#define PTRS_PER_PMD (1UL << (PAGE_SHIFT-3)) - -/* - * Definitions for third level: - */ -#define PTRS_PER_PTE (__IA64_UL(1) << (PAGE_SHIFT-3)) - -/* - * All the normal masks have the "page accessed" bits on, as any time - * they are used, the page is accessed. They are cleared only by the - * page-out routines. - */ -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_A) -#define PAGE_SHARED __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RW) -#define PAGE_READONLY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) -#define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) -#define PAGE_COPY_EXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) -#define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) -#define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) -#define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX) - -# ifndef __ASSEMBLY__ - -#include <asm/bitops.h> -#include <asm/cacheflush.h> -#include <asm/mmu_context.h> -#include <asm/processor.h> - -/* - * Next come the mappings that determine how mmap() protection bits - * (PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE) get implemented. The - * _P version gets used for a private shared memory segment, the _S - * version gets used for a shared memory segment with MAP_SHARED on. - * In a private shared memory segment, we do a copy-on-write if a task - * attempts to write to the page. - */ - /* xwr */ -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_READONLY /* write to priv pg -> copy & make writable */ -#define __P011 PAGE_READONLY /* ditto */ -#define __P100 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_X_RX) -#define __P101 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) -#define __P110 PAGE_COPY_EXEC -#define __P111 PAGE_COPY_EXEC - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED /* we don't have (and don't need) write-only */ -#define __S011 PAGE_SHARED -#define __S100 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_X_RX) -#define __S101 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) -#define __S110 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RWX) -#define __S111 __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RWX) - -#define pgd_ERROR(e) printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) -#define pmd_ERROR(e) printk("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) -#define pte_ERROR(e) printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) - - -/* - * Some definitions to translate between mem_map, PTEs, and page addresses: - */ - - -/* Quick test to see if ADDR is a (potentially) valid physical address. */ -static inline long -ia64_phys_addr_valid (unsigned long addr) -{ - return (addr & (local_cpu_data->unimpl_pa_mask)) == 0; -} - -/* - * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel - * memory. For the return value to be meaningful, ADDR must be >= - * PAGE_OFFSET. This operation can be relatively expensive (e.g., - * require a hash-, or multi-level tree-lookup or something of that - * sort) but it guarantees to return TRUE only if accessing the page - * at that address does not cause an error. Note that there may be - * addresses for which kern_addr_valid() returns FALSE even though an - * access would not cause an error (e.g., this is typically true for - * memory mapped I/O regions. - * - * XXX Need to implement this for IA-64. - */ -#define kern_addr_valid(addr) (1) - - -/* - * Now come the defines and routines to manage and access the three-level - * page table. - */ - -/* - * On some architectures, special things need to be done when setting - * the PTE in a page table. Nothing special needs to be on IA-64. - */ -#define set_pte(ptep, pteval) (*(ptep) = (pteval)) - -#define RGN_SIZE (1UL << 61) -#define RGN_KERNEL 7 - -#define VMALLOC_START 0xa000000200000000UL -#ifdef CONFIG_VIRTUAL_MEM_MAP -# define VMALLOC_END_INIT (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9))) -# define VMALLOC_END vmalloc_end - extern unsigned long vmalloc_end; -#else -# define VMALLOC_END (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9))) -#endif - -/* fs/proc/kcore.c */ -#define kc_vaddr_to_offset(v) ((v) - 0xa000000000000000UL) -#define kc_offset_to_vaddr(o) ((o) + 0xa000000000000000UL) - -/* - * Conversion functions: convert page frame number (pfn) and a protection value to a page - * table entry (pte). - */ -#define pfn_pte(pfn, pgprot) \ -({ pte_t __pte; pte_val(__pte) = ((pfn) << PAGE_SHIFT) | pgprot_val(pgprot); __pte; }) - -/* Extract pfn from pte. */ -#define pte_pfn(_pte) ((pte_val(_pte) & _PFN_MASK) >> PAGE_SHIFT) - -#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) - -/* This takes a physical page address that is used by the remapping functions */ -#define mk_pte_phys(physpage, pgprot) \ -({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; }) - -#define pte_modify(_pte, newprot) \ - (__pte((pte_val(_pte) & ~_PAGE_CHG_MASK) | (pgprot_val(newprot) & _PAGE_CHG_MASK))) - -#define page_pte_prot(page,prot) mk_pte(page, prot) -#define page_pte(page) page_pte_prot(page, __pgprot(0)) - -#define pte_none(pte) (!pte_val(pte)) -#define pte_present(pte) (pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE)) -#define pte_clear(pte) (pte_val(*(pte)) = 0UL) -/* pte_page() returns the "struct page *" corresponding to the PTE: */ -#define pte_page(pte) virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET)) - -#define pmd_none(pmd) (!pmd_val(pmd)) -#define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd))) -#define pmd_present(pmd) (pmd_val(pmd) != 0UL) -#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) -#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK)) -#define pmd_page(pmd) virt_to_page((pmd_val(pmd) + PAGE_OFFSET)) - -#define pud_none(pud) (!pud_val(pud)) -#define pud_bad(pud) (!ia64_phys_addr_valid(pud_val(pud))) -#define pud_present(pud) (pud_val(pud) != 0UL) -#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) - -#define pud_page(pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK)) - -/* - * The following have defined behavior only work if pte_present() is true. - */ -#define pte_user(pte) ((pte_val(pte) & _PAGE_PL_MASK) == _PAGE_PL_3) -#define pte_read(pte) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) < 6) -#define pte_write(pte) ((unsigned) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) - 2) <= 4) -#define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0) -#define pte_dirty(pte) ((pte_val(pte) & _PAGE_D) != 0) -#define pte_young(pte) ((pte_val(pte) & _PAGE_A) != 0) -#define pte_file(pte) ((pte_val(pte) & _PAGE_FILE) != 0) -/* - * Note: we convert AR_RWX to AR_RX and AR_RW to AR_R by clearing the 2nd bit in the - * access rights: - */ -#define pte_wrprotect(pte) (__pte(pte_val(pte) & ~_PAGE_AR_RW)) -#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_AR_RW)) -#define pte_mkexec(pte) (__pte(pte_val(pte) | _PAGE_AR_RX)) -#define pte_mkold(pte) (__pte(pte_val(pte) & ~_PAGE_A)) -#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_A)) -#define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D)) -#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D)) - -/* - * Macro to a page protection value as "uncacheable". Note that "protection" is really a - * misnomer here as the protection value contains the memory attribute bits, dirty bits, - * and various other bits as well. - */ -#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) - -/* - * Macro to make mark a page protection value as "write-combining". - * Note that "protection" is really a misnomer here as the protection - * value contains the memory attribute bits, dirty bits, and various - * other bits as well. Accesses through a write-combining translation - * works bypasses the caches, but does allow for consecutive writes to - * be combined into single (but larger) write transactions. - */ -#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) - -static inline unsigned long -pgd_index (unsigned long address) -{ - unsigned long region = address >> 61; - unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1); - - return (region << (PAGE_SHIFT - 6)) | l1index; -} - -/* The offset in the 1-level directory is given by the 3 region bits - (61..63) and the level-1 bits. */ -static inline pgd_t* -pgd_offset (struct mm_struct *mm, unsigned long address) -{ - return mm->pgd + pgd_index(address); -} - -/* In the kernel's mapped region we completely ignore the region number - (since we know it's in region number 5). */ -#define pgd_offset_k(addr) \ - (init_mm.pgd + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))) - -/* Look up a pgd entry in the gate area. On IA-64, the gate-area - resides in the kernel-mapped segment, hence we use pgd_offset_k() - here. */ -#define pgd_offset_gate(mm, addr) pgd_offset_k(addr) - -/* Find an entry in the second-level page table.. */ -#define pmd_offset(dir,addr) \ - ((pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) - -/* - * Find an entry in the third-level page table. This looks more complicated than it - * should be because some platforms place page tables in high memory. - */ -#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr)) -#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr) -#define pte_offset_map_nested(dir,addr) pte_offset_map(dir, addr) -#define pte_unmap(pte) do { } while (0) -#define pte_unmap_nested(pte) do { } while (0) - -/* atomic versions of the some PTE manipulations: */ - -static inline int -ptep_test_and_clear_young (pte_t *ptep) -{ -#ifdef CONFIG_SMP - if (!pte_young(*ptep)) - return 0; - return test_and_clear_bit(_PAGE_A_BIT, ptep); -#else - pte_t pte = *ptep; - if (!pte_young(pte)) - return 0; - set_pte(ptep, pte_mkold(pte)); - return 1; -#endif -} - -static inline int -ptep_test_and_clear_dirty (pte_t *ptep) -{ -#ifdef CONFIG_SMP - if (!pte_dirty(*ptep)) - return 0; - return test_and_clear_bit(_PAGE_D_BIT, ptep); -#else - pte_t pte = *ptep; - if (!pte_dirty(pte)) - return 0; - set_pte(ptep, pte_mkclean(pte)); - return 1; -#endif -} - -static inline pte_t -ptep_get_and_clear (pte_t *ptep) -{ -#ifdef CONFIG_SMP - return __pte(xchg((long *) ptep, 0)); -#else - pte_t pte = *ptep; - pte_clear(ptep); - return pte; -#endif -} - -static inline void -ptep_set_wrprotect (pte_t *ptep) -{ -#ifdef CONFIG_SMP - unsigned long new, old; - - do { - old = pte_val(*ptep); - new = pte_val(pte_wrprotect(__pte (old))); - } while (cmpxchg((unsigned long *) ptep, old, new) != old); -#else - pte_t old_pte = *ptep; - set_pte(ptep, pte_wrprotect(old_pte)); -#endif -} - -static inline void -ptep_mkdirty (pte_t *ptep) -{ -#ifdef CONFIG_SMP - set_bit(_PAGE_D_BIT, ptep); -#else - pte_t old_pte = *ptep; - set_pte(ptep, pte_mkdirty(old_pte)); -#endif -} - -static inline int -pte_same (pte_t a, pte_t b) -{ - return pte_val(a) == pte_val(b); -} - -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; -extern void paging_init (void); - -/* - * Note: The macros below rely on the fact that MAX_SWAPFILES_SHIFT <= number of - * bits in the swap-type field of the swap pte. It would be nice to - * enforce that, but we can't easily include <linux/swap.h> here. - * (Of course, better still would be to define MAX_SWAPFILES_SHIFT here...). - * - * Format of swap pte: - * bit 0 : present bit (must be zero) - * bit 1 : _PAGE_FILE (must be zero) - * bits 2- 8: swap-type - * bits 9-62: swap offset - * bit 63 : _PAGE_PROTNONE bit - * - * Format of file pte: - * bit 0 : present bit (must be zero) - * bit 1 : _PAGE_FILE (must be one) - * bits 2-62: file_offset/PAGE_SIZE - * bit 63 : _PAGE_PROTNONE bit - */ -#define __swp_type(entry) (((entry).val >> 2) & 0x7f) -#define __swp_offset(entry) (((entry).val << 1) >> 10) -#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((long) (offset) << 9) }) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) - -#define PTE_FILE_MAX_BITS 61 -#define pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE }) - -/* XXX is this right? */ -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - -/* - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; -extern struct page *zero_page_memmap_ptr; -#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr) - -/* We provide our own get_unmapped_area to cope with VA holes for userland */ -#define HAVE_ARCH_UNMAPPED_AREA - -#ifdef CONFIG_HUGETLB_PAGE -#define HUGETLB_PGDIR_SHIFT (HPAGE_SHIFT + 2*(PAGE_SHIFT-3)) -#define HUGETLB_PGDIR_SIZE (__IA64_UL(1) << HUGETLB_PGDIR_SHIFT) -#define HUGETLB_PGDIR_MASK (~(HUGETLB_PGDIR_SIZE-1)) -struct mmu_gather; -extern void hugetlb_free_pgtables(struct mmu_gather *tlb, - struct vm_area_struct * prev, unsigned long start, unsigned long end); -#endif - -/* - * IA-64 doesn't have any external MMU info: the page tables contain all the necessary - * information. However, we use this routine to take care of any (delayed) i-cache - * flushing that may be necessary. - */ -extern void update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte); - -#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS -/* - * Update PTEP with ENTRY, which is guaranteed to be a less - * restrictive PTE. That is, ENTRY may have the ACCESSED, DIRTY, and - * WRITABLE bits turned on, when the value at PTEP did not. The - * WRITABLE bit may only be turned if SAFELY_WRITABLE is TRUE. - * - * SAFELY_WRITABLE is TRUE if we can update the value at PTEP without - * having to worry about races. On SMP machines, there are only two - * cases where this is true: - * - * (1) *PTEP has the PRESENT bit turned OFF - * (2) ENTRY has the DIRTY bit turned ON - * - * On ia64, we could implement this routine with a cmpxchg()-loop - * which ORs in the _PAGE_A/_PAGE_D bit if they're set in ENTRY. - * However, like on x86, we can get a more streamlined version by - * observing that it is OK to drop ACCESSED bit updates when - * SAFELY_WRITABLE is FALSE. Besides being rare, all that would do is - * result in an extra Access-bit fault, which would then turn on the - * ACCESSED bit in the low-level fault handler (iaccess_bit or - * daccess_bit in ivt.S). - */ -#ifdef CONFIG_SMP -# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \ -do { \ - if (__safely_writable) { \ - set_pte(__ptep, __entry); \ - flush_tlb_page(__vma, __addr); \ - } \ -} while (0) -#else -# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \ - ptep_establish(__vma, __addr, __ptep, __entry) -#endif - -# ifdef CONFIG_VIRTUAL_MEM_MAP - /* arch mem_map init routine is needed due to holes in a virtual mem_map */ -# define __HAVE_ARCH_MEMMAP_INIT - extern void memmap_init (unsigned long size, int nid, unsigned long zone, - unsigned long start_pfn); -# endif /* CONFIG_VIRTUAL_MEM_MAP */ -# endif /* !__ASSEMBLY__ */ - -/* - * Identity-mapped regions use a large page size. We'll call such large pages - * "granules". If you can think of a better name that's unambiguous, let me - * know... - */ -#if defined(CONFIG_IA64_GRANULE_64MB) -# define IA64_GRANULE_SHIFT _PAGE_SIZE_64M -#elif defined(CONFIG_IA64_GRANULE_16MB) -# define IA64_GRANULE_SHIFT _PAGE_SIZE_16M -#endif -#define IA64_GRANULE_SIZE (1 << IA64_GRANULE_SHIFT) -/* - * log2() of the page size we use to map the kernel image (IA64_TR_KERNEL): - */ -#define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M -#define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) - -/* - * No page table caches to initialise - */ -#define pgtable_cache_init() do { } while (0) - -/* These tell get_user_pages() that the first gate page is accessible from user-level. */ -#define FIXADDR_USER_START GATE_ADDR -#define FIXADDR_USER_END (GATE_ADDR + 2*PERCPU_PAGE_SIZE) - -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY -#define __HAVE_ARCH_PTEP_GET_AND_CLEAR -#define __HAVE_ARCH_PTEP_SET_WRPROTECT -#define __HAVE_ARCH_PTEP_MKDIRTY -#define __HAVE_ARCH_PTE_SAME -#define __HAVE_ARCH_PGD_OFFSET_GATE -#include <asm-generic/pgtable.h> -#include <asm-generic/pgtable-nopud.h> - -#endif /* _ASM_IA64_PGTABLE_H */ diff -r d34925e4144b -r 3ca4ca7a9cc2 xen/include/asm-ia64/linux/linuxtime.h --- a/xen/include/asm-ia64/linux/linuxtime.h Thu Sep 1 17:09:27 2005 +++ /dev/null Thu Sep 1 18:46:28 2005 @@ -1,181 +0,0 @@ -#ifndef _LINUX_TIME_H -#define _LINUX_TIME_H - -#include <linux/types.h> - -#ifdef __KERNEL__ -#include <linux/seqlock.h> -#endif - -#ifndef _STRUCT_TIMESPEC -#define _STRUCT_TIMESPEC -struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; -#endif /* _STRUCT_TIMESPEC */ - -struct timeval { - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* microseconds */ -}; - -struct timezone { - int tz_minuteswest; /* minutes west of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -#ifdef __KERNEL__ - -/* Parameters used to convert the timespec values */ -#ifndef USEC_PER_SEC -#define USEC_PER_SEC (1000000L) -#endif - -#ifndef NSEC_PER_SEC -#define NSEC_PER_SEC (1000000000L) -#endif - -#ifndef NSEC_PER_USEC -#define NSEC_PER_USEC (1000L) -#endif - -static __inline__ int timespec_equal(struct timespec *a, struct timespec *b) -{ - return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec); -} - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long -mktime (unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - - return ((( - (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - -extern struct timespec xtime; -extern struct timespec wall_to_monotonic; -extern seqlock_t xtime_lock; - -static inline unsigned long get_seconds(void) -{ - return xtime.tv_sec; -} - -struct timespec current_kernel_time(void); - -#define CURRENT_TIME (current_kernel_time()) -#define CURRENT_TIME_SEC ((struct timespec) { xtime.tv_sec, 0 }) - -extern void do_gettimeofday(struct timeval *tv); -extern int do_settimeofday(struct timespec *tv); -extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz); -extern void clock_was_set(void); // call when ever the clock is set -extern int do_posix_clock_monotonic_gettime(struct timespec *tp); -extern long do_nanosleep(struct timespec *t); -extern long do_utimes(char __user * filename, struct timeval * times); -struct itimerval; -extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue); -extern int do_getitimer(int which, struct itimerval *value); -extern void getnstimeofday (struct timespec *tv); - -extern struct timespec timespec_trunc(struct timespec t, unsigned gran); - -static inline void -set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) -{ - while (nsec > NSEC_PER_SEC) { - nsec -= NSEC_PER_SEC; - ++sec; - } - while (nsec < 0) { - nsec += NSEC_PER_SEC; - --sec; - } - ts->tv_sec = sec; - ts->tv_nsec = nsec; -} - -#endif /* __KERNEL__ */ - -#define NFDBITS __NFDBITS - -#define FD_SETSIZE __FD_SETSIZE -#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp) -#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp) -#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp) -#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp) - -/* - * Names of the interval timers, and structure - * defining a timer setting. - */ -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 - -struct itimerspec { - struct timespec it_interval; /* timer period */ - struct timespec it_value; /* timer expiration */ -}; - -struct itimerval { - struct timeval it_interval; /* timer interval */ - struct timeval it_value; /* current value */ -}; - - -/* - * The IDs of the various system clocks (for POSIX.1b interval timers). - */ -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCK_PROCESS_CPUTIME_ID 2 -#define CLOCK_THREAD_CPUTIME_ID 3 -#define CLOCK_REALTIME_HR 4 -#define CLOCK_MONOTONIC_HR 5 - -/* - * The IDs of various hardware clocks - */ - - -#define CLOCK_SGI_CYCLE 10 -#define MAX_CLOCKS 16 -#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC | \ - CLOCK_REALTIME_HR | CLOCK_MONOTONIC_HR) -#define CLOCKS_MONO (CLOCK_MONOTONIC & CLOCK_MONOTONIC_HR) - -/* - * The various flags for setting POSIX.1b interval timers. - */ - -#define TIMER_ABSTIME 0x01 - - -#endif _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |