From 107d6d2efa9eb8c48d050936d8019230ac6b24cd Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 5 May 2008 14:58:26 +0300 Subject: KVM: x86 emulator: fix writes to registers with modrm encodings A register destination encoded with a mod=3 encoding left dst.ptr NULL. Normally we don't trap writes to registers, but in the case of smsw, we do. Fix by pointing dst.ptr at the destination register. Signed-off-by: Avi Kivity --- include/asm-x86/kvm_x86_emulate.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/asm-x86') diff --git a/include/asm-x86/kvm_x86_emulate.h b/include/asm-x86/kvm_x86_emulate.h index d6337f941c9..b877bbd2d3a 100644 --- a/include/asm-x86/kvm_x86_emulate.h +++ b/include/asm-x86/kvm_x86_emulate.h @@ -135,6 +135,7 @@ struct decode_cache { u8 modrm_rm; u8 use_modrm_ea; unsigned long modrm_ea; + void *modrm_ptr; unsigned long modrm_val; struct fetch_cache fetch; }; -- cgit v1.2.3-18-g5258 From 2bd3a99c9d1851182f73d0a024dc5bdb0a470e8c Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:17 +0100 Subject: x86: define PTE_MASK in a universally useful way Define PTE_MASK so that it contains a meaningful value for all x86 pagetable configurations. Previously it was defined as a "long" which means that it was too short to cover a 32-bit PAE pte entry. It is now defined as a pteval_t, which is an integer type long enough to contain a full pte (or pmd, pud, pgd). This fixes an Xorg crash on 32-bit x86 with PAE due to corruption of the NX bit in mprotect due to the incorrect type/value of PTE_MASK reported by Hugh Dickins: "Yes, thanks Jeremy: I've checked that each stage builds and runs X on my boxes here, x86_32 and x86_32+PAE and x86_64. (So even 1/8 is enough to fix the PAT pte_modify issue, though 2/8 then fixes compiler warnings.)" Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/page.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index b381f4a5a0b..76b35e636d7 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h @@ -10,8 +10,13 @@ #ifdef __KERNEL__ -#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK) -#define PTE_MASK (_AT(long, PHYSICAL_PAGE_MASK)) +/* Cast PAGE_MASK to a signed type so that it is sign-extended if + virtual addresses are 32-bits but physical addresses are larger + (ie, 32-bit PAE). */ +#define PHYSICAL_PAGE_MASK (((signed long)PAGE_MASK) & __PHYSICAL_MASK) + +/* PTE_MASK extracts the PFN from a (pte|pmd|pud|pgd)val_t */ +#define PTE_MASK ((pteval_t)PHYSICAL_PAGE_MASK) #define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT) #define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1)) @@ -24,8 +29,8 @@ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -#define __PHYSICAL_MASK _AT(phys_addr_t, (_AC(1,ULL) << __PHYSICAL_MASK_SHIFT) - 1) -#define __VIRTUAL_MASK ((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1) +#define __PHYSICAL_MASK ((((phys_addr_t)1) << __PHYSICAL_MASK_SHIFT) - 1) +#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) #ifndef __ASSEMBLY__ #include -- cgit v1.2.3-18-g5258 From 1bb271db63c356212564aad050b2cf026f800858 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:18 +0100 Subject: x86: fix warning on 32-bit non-PAE Fix the warning: include2/asm/pgtable.h: In function `pte_modify': include2/asm/pgtable.h:290: warning: left shift count >= width of type On 32-bit PAE the virtual and physical addresses are both 32-bits, so it ends up evaluating 1<<32. Do the shift as a 64-bit shift then cast to the appropriate size. This should all be done at compile time, and so have no effect on generated code. Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index 76b35e636d7..223146da2fa 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h @@ -29,7 +29,7 @@ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -#define __PHYSICAL_MASK ((((phys_addr_t)1) << __PHYSICAL_MASK_SHIFT) - 1) +#define __PHYSICAL_MASK ((phys_addr_t)(1ULL << __PHYSICAL_MASK_SHIFT) - 1) #define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) #ifndef __ASSEMBLY__ -- cgit v1.2.3-18-g5258 From c57c05d0032cd5a500c5eba18ede4867a6d2cd5f Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:19 +0100 Subject: x86: rearrange __(VIRTUAL|PHYSICAL)_MASK Put the definitions of __(VIRTUAL|PHYSICAL)_MASK before their uses. Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/page.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index 223146da2fa..dc936dddf16 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h @@ -10,6 +10,9 @@ #ifdef __KERNEL__ +#define __PHYSICAL_MASK ((phys_addr_t)(1ULL << __PHYSICAL_MASK_SHIFT) - 1) +#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) + /* Cast PAGE_MASK to a signed type so that it is sign-extended if virtual addresses are 32-bits but physical addresses are larger (ie, 32-bit PAE). */ @@ -29,9 +32,6 @@ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -#define __PHYSICAL_MASK ((phys_addr_t)(1ULL << __PHYSICAL_MASK_SHIFT) - 1) -#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) - #ifndef __ASSEMBLY__ #include #endif -- cgit v1.2.3-18-g5258 From a4d6886270a5c892d71cd6e09186196a150a50dc Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:20 +0100 Subject: x86: use PTE_MASK in 32-bit PAE Use PTE_MASK in 3-level pagetables (ie, 32-bit PAE). Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/pgtable-3level.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgtable-3level.h b/include/asm-x86/pgtable-3level.h index 8b4a9d44b7f..c93dbb6c262 100644 --- a/include/asm-x86/pgtable-3level.h +++ b/include/asm-x86/pgtable-3level.h @@ -120,9 +120,9 @@ static inline void pud_clear(pud_t *pudp) write_cr3(pgd); } -#define pud_page(pud) ((struct page *) __va(pud_val(pud) & PAGE_MASK)) +#define pud_page(pud) ((struct page *) __va(pud_val(pud) & PTE_MASK)) -#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK)) +#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PTE_MASK)) /* Find an entry in the second-level page table.. */ @@ -160,7 +160,7 @@ static inline int pte_none(pte_t pte) static inline unsigned long pte_pfn(pte_t pte) { - return (pte_val(pte) & ~_PAGE_NX) >> PAGE_SHIFT; + return (pte_val(pte) & PTE_MASK) >> PAGE_SHIFT; } /* -- cgit v1.2.3-18-g5258 From 7f84133af6aaa86e9ef0e9e1970655439a8cf3a1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:21 +0100 Subject: x86: use PTE_MASK in pgtable_32.h Signed-off-by: Linus Torvalds --- include/asm-x86/pgtable_32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h index d7f0403bbec..32ca03109a4 100644 --- a/include/asm-x86/pgtable_32.h +++ b/include/asm-x86/pgtable_32.h @@ -88,7 +88,7 @@ extern unsigned long pg0[]; /* To avoid harmful races, pmd_none(x) should check only the lower when PAE */ #define pmd_none(x) (!(unsigned long)pmd_val((x))) #define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT) -#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pmd_bad(x) ((pmd_val(x) & (~PTE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) @@ -159,7 +159,7 @@ static inline int pud_large(pud_t pud) { return 0; } #define pmd_page(pmd) (pfn_to_page(pmd_val((pmd)) >> PAGE_SHIFT)) #define pmd_page_vaddr(pmd) \ - ((unsigned long)__va(pmd_val((pmd)) & PAGE_MASK)) + ((unsigned long)__va(pmd_val((pmd)) & PTE_MASK)) #if defined(CONFIG_HIGHPTE) #define pte_offset_map(dir, address) \ -- cgit v1.2.3-18-g5258 From 86aaf4fd4ea25ddde05772d03b93dbce23c0ead1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:22 +0100 Subject: x86: clarify use of _PAGE_CHG_MASK _PAGE_CHG_MASK is defined as the set of bits not updated by pte_modify(); specifically, the pfn itself, and the Accessed and Dirty bits (which are updated by hardware). Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/pgtable.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index 55c3a0e3a8c..b816134f753 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h @@ -57,6 +57,7 @@ #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | \ _PAGE_DIRTY) +/* Set of bits not changed in pte_modify */ #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_PCD | _PAGE_PWT | \ _PAGE_ACCESSED | _PAGE_DIRTY) -- cgit v1.2.3-18-g5258 From ba23cef5c23cf1e9298032037d919157553d1211 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:23 +0100 Subject: x86: use PTE_MASK rather than ad-hoc mask Use ~PTE_MASK to extract the non-pfn parts of the pte (ie, the pte flags), rather than constructing an ad-hoc mask. Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index b816134f753..97c271b2910 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h @@ -305,7 +305,7 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) return __pgprot(preservebits | addbits); } -#define pte_pgprot(x) __pgprot(pte_val(x) & (0xfff | _PAGE_NX)) +#define pte_pgprot(x) __pgprot(pte_val(x) & ~PTE_MASK) #define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask) -- cgit v1.2.3-18-g5258 From cbb3077cbe718795d7ae5d78ed11659ca73c97b9 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 20 May 2008 08:26:24 +0100 Subject: xen: use PTE_MASK in pte_mfn() Use PTE_MASK to extract mfn from pte. Signed-off-by: Jeremy Fitzhardinge Tested-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/xen/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h index 01799305f02..baf3a4dce28 100644 --- a/include/asm-x86/xen/page.h +++ b/include/asm-x86/xen/page.h @@ -127,7 +127,7 @@ static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) static inline unsigned long pte_mfn(pte_t pte) { - return (pte.pte & ~_PAGE_NX) >> PAGE_SHIFT; + return (pte.pte & PTE_MASK) >> PAGE_SHIFT; } static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot) -- cgit v1.2.3-18-g5258 From a8375bd81cf99cb81be37127eaf08316ecb87619 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 20 May 2008 13:59:47 +0100 Subject: x86: strengthen 64-bit p?d_bad() The x86_64 pgd_bad(), pud_bad(), pmd_bad() inlines have differed from their x86_32 counterparts in a couple of ways: they've been unnecessarily weak (e.g. letting 0 or 1 count as good), and were typed as unsigned long. Strengthen them and return int. The PAE pmd_bad was too weak before, allowing any junk in the upper half; but got strengthened by the patch correcting its ~PAGE_MASK to ~PTE_MASK. The PAE pud_bad already said ~PTE_MASK; and since it folds into pgd_bad, and we don't set the protection bits at that level, it'll do as is. Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/asm-x86/pgtable_64.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h index efe83dcbd41..1cc50d22d73 100644 --- a/include/asm-x86/pgtable_64.h +++ b/include/asm-x86/pgtable_64.h @@ -151,19 +151,19 @@ static inline void native_pgd_clear(pgd_t *pgd) #ifndef __ASSEMBLY__ -static inline unsigned long pgd_bad(pgd_t pgd) +static inline int pgd_bad(pgd_t pgd) { - return pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); + return (pgd_val(pgd) & ~(PTE_MASK | _PAGE_USER)) != _KERNPG_TABLE; } -static inline unsigned long pud_bad(pud_t pud) +static inline int pud_bad(pud_t pud) { - return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); + return (pud_val(pud) & ~(PTE_MASK | _PAGE_USER)) != _KERNPG_TABLE; } -static inline unsigned long pmd_bad(pmd_t pmd) +static inline int pmd_bad(pmd_t pmd) { - return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); + return (pmd_val(pmd) & ~(PTE_MASK | _PAGE_USER)) != _KERNPG_TABLE; } #define pte_none(x) (!pte_val((x))) -- cgit v1.2.3-18-g5258 From b1979a5fda7869a790f4fd83fb06c78498d26ba1 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 12 May 2008 21:21:15 +0200 Subject: x86: prevent PGE flush from interruption/preemption CR4 manipulation is not protected against interrupts and preemption, but KVM uses smp_function_call to manipulate the X86_CR4_VMXE bit either from the CPU hotplug code or from the kvm_init call. We need to protect the CR4 manipulation from both interrupts and preemption. Original bug report: http://lkml.org/lkml/2008/5/7/48 Bugzilla entry: http://bugzilla.kernel.org/show_bug.cgi?id=10642 This is not a regression from 2.6.25, it's a long standing and hard to trigger bug. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- include/asm-x86/tlbflush.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/tlbflush.h b/include/asm-x86/tlbflush.h index 0c0674d9425..35c76ceb9f4 100644 --- a/include/asm-x86/tlbflush.h +++ b/include/asm-x86/tlbflush.h @@ -22,12 +22,23 @@ static inline void __native_flush_tlb(void) static inline void __native_flush_tlb_global(void) { - unsigned long cr4 = read_cr4(); + unsigned long flags; + unsigned long cr4; + /* + * Read-modify-write to CR4 - protect it from preemption and + * from interrupts. (Use the raw variant because this code can + * be called from deep inside debugging code.) + */ + raw_local_irq_save(flags); + + cr4 = read_cr4(); /* clear PGE */ write_cr4(cr4 & ~X86_CR4_PGE); /* write old PGE again and flush TLBs */ write_cr4(cr4); + + raw_local_irq_restore(flags); } static inline void __native_flush_tlb_single(unsigned long addr) -- cgit v1.2.3-18-g5258