diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-02-04 17:46:34 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2010-06-07 14:32:33 -0400 |
commit | c0011dbfce69467b23b08fb4a64c39a409a935fb (patch) | |
tree | 47ecf9ee630f58d49edd2fd18fdc0159eb486392 | |
parent | e40152ee1e1c7a63f4777791863215e3faa37a86 (diff) |
xen: use _PAGE_IOMAP in ioremap to do machine mappings
In a Xen domain, ioremap operates on machine addresses, not
pseudo-physical addresses. We use _PAGE_IOMAP to determine whether a
mapping is intended for machine addresses.
[ Impact: allow Xen domain to map real hardware ]
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r-- | arch/x86/include/asm/xen/page.h | 8 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 71 |
2 files changed, 71 insertions, 8 deletions
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 018a0a400799..bf5f7d32bd08 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h | |||
@@ -112,13 +112,9 @@ static inline xpaddr_t machine_to_phys(xmaddr_t machine) | |||
112 | */ | 112 | */ |
113 | static inline unsigned long mfn_to_local_pfn(unsigned long mfn) | 113 | static inline unsigned long mfn_to_local_pfn(unsigned long mfn) |
114 | { | 114 | { |
115 | extern unsigned long max_mapnr; | ||
116 | unsigned long pfn = mfn_to_pfn(mfn); | 115 | unsigned long pfn = mfn_to_pfn(mfn); |
117 | if ((pfn < max_mapnr) | 116 | if (get_phys_to_machine(pfn) != mfn) |
118 | && !xen_feature(XENFEAT_auto_translated_physmap) | 117 | return -1; /* force !pfn_valid() */ |
119 | && (get_phys_to_machine(pfn) != mfn)) | ||
120 | return max_mapnr; /* force !pfn_valid() */ | ||
121 | /* XXX fixme; not true with sparsemem */ | ||
122 | return pfn; | 118 | return pfn; |
123 | } | 119 | } |
124 | 120 | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 914f04695ce5..a4dea9df0cc0 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -56,9 +56,11 @@ | |||
56 | #include <asm/xen/hypercall.h> | 56 | #include <asm/xen/hypercall.h> |
57 | #include <asm/xen/hypervisor.h> | 57 | #include <asm/xen/hypervisor.h> |
58 | 58 | ||
59 | #include <xen/xen.h> | ||
59 | #include <xen/page.h> | 60 | #include <xen/page.h> |
60 | #include <xen/interface/xen.h> | 61 | #include <xen/interface/xen.h> |
61 | #include <xen/interface/version.h> | 62 | #include <xen/interface/version.h> |
63 | #include <xen/interface/memory.h> | ||
62 | #include <xen/hvc-console.h> | 64 | #include <xen/hvc-console.h> |
63 | 65 | ||
64 | #include "multicalls.h" | 66 | #include "multicalls.h" |
@@ -377,6 +379,28 @@ static bool xen_page_pinned(void *ptr) | |||
377 | return PagePinned(page); | 379 | return PagePinned(page); |
378 | } | 380 | } |
379 | 381 | ||
382 | static bool xen_iomap_pte(pte_t pte) | ||
383 | { | ||
384 | return xen_initial_domain() && (pte_flags(pte) & _PAGE_IOMAP); | ||
385 | } | ||
386 | |||
387 | static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval) | ||
388 | { | ||
389 | struct multicall_space mcs; | ||
390 | struct mmu_update *u; | ||
391 | |||
392 | mcs = xen_mc_entry(sizeof(*u)); | ||
393 | u = mcs.args; | ||
394 | |||
395 | /* ptep might be kmapped when using 32-bit HIGHPTE */ | ||
396 | u->ptr = arbitrary_virt_to_machine(ptep).maddr; | ||
397 | u->val = pte_val_ma(pteval); | ||
398 | |||
399 | MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_IO); | ||
400 | |||
401 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
402 | } | ||
403 | |||
380 | static void xen_extend_mmu_update(const struct mmu_update *update) | 404 | static void xen_extend_mmu_update(const struct mmu_update *update) |
381 | { | 405 | { |
382 | struct multicall_space mcs; | 406 | struct multicall_space mcs; |
@@ -453,6 +477,11 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags) | |||
453 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | 477 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, |
454 | pte_t *ptep, pte_t pteval) | 478 | pte_t *ptep, pte_t pteval) |
455 | { | 479 | { |
480 | if (xen_iomap_pte(pteval)) { | ||
481 | xen_set_iomap_pte(ptep, pteval); | ||
482 | goto out; | ||
483 | } | ||
484 | |||
456 | ADD_STATS(set_pte_at, 1); | 485 | ADD_STATS(set_pte_at, 1); |
457 | // ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); | 486 | // ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); |
458 | ADD_STATS(set_pte_at_current, mm == current->mm); | 487 | ADD_STATS(set_pte_at_current, mm == current->mm); |
@@ -523,8 +552,25 @@ static pteval_t pte_pfn_to_mfn(pteval_t val) | |||
523 | return val; | 552 | return val; |
524 | } | 553 | } |
525 | 554 | ||
555 | static pteval_t iomap_pte(pteval_t val) | ||
556 | { | ||
557 | if (val & _PAGE_PRESENT) { | ||
558 | unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; | ||
559 | pteval_t flags = val & PTE_FLAGS_MASK; | ||
560 | |||
561 | /* We assume the pte frame number is a MFN, so | ||
562 | just use it as-is. */ | ||
563 | val = ((pteval_t)pfn << PAGE_SHIFT) | flags; | ||
564 | } | ||
565 | |||
566 | return val; | ||
567 | } | ||
568 | |||
526 | pteval_t xen_pte_val(pte_t pte) | 569 | pteval_t xen_pte_val(pte_t pte) |
527 | { | 570 | { |
571 | if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP)) | ||
572 | return pte.pte; | ||
573 | |||
528 | return pte_mfn_to_pfn(pte.pte); | 574 | return pte_mfn_to_pfn(pte.pte); |
529 | } | 575 | } |
530 | PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val); | 576 | PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val); |
@@ -537,7 +583,11 @@ PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val); | |||
537 | 583 | ||
538 | pte_t xen_make_pte(pteval_t pte) | 584 | pte_t xen_make_pte(pteval_t pte) |
539 | { | 585 | { |
540 | pte = pte_pfn_to_mfn(pte); | 586 | if (unlikely(xen_initial_domain() && (pte & _PAGE_IOMAP))) |
587 | pte = iomap_pte(pte); | ||
588 | else | ||
589 | pte = pte_pfn_to_mfn(pte); | ||
590 | |||
541 | return native_make_pte(pte); | 591 | return native_make_pte(pte); |
542 | } | 592 | } |
543 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); | 593 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); |
@@ -593,6 +643,11 @@ void xen_set_pud(pud_t *ptr, pud_t val) | |||
593 | 643 | ||
594 | void xen_set_pte(pte_t *ptep, pte_t pte) | 644 | void xen_set_pte(pte_t *ptep, pte_t pte) |
595 | { | 645 | { |
646 | if (xen_iomap_pte(pte)) { | ||
647 | xen_set_iomap_pte(ptep, pte); | ||
648 | return; | ||
649 | } | ||
650 | |||
596 | ADD_STATS(pte_update, 1); | 651 | ADD_STATS(pte_update, 1); |
597 | // ADD_STATS(pte_update_pinned, xen_page_pinned(ptep)); | 652 | // ADD_STATS(pte_update_pinned, xen_page_pinned(ptep)); |
598 | ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU); | 653 | ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU); |
@@ -609,6 +664,11 @@ void xen_set_pte(pte_t *ptep, pte_t pte) | |||
609 | #ifdef CONFIG_X86_PAE | 664 | #ifdef CONFIG_X86_PAE |
610 | void xen_set_pte_atomic(pte_t *ptep, pte_t pte) | 665 | void xen_set_pte_atomic(pte_t *ptep, pte_t pte) |
611 | { | 666 | { |
667 | if (xen_iomap_pte(pte)) { | ||
668 | xen_set_iomap_pte(ptep, pte); | ||
669 | return; | ||
670 | } | ||
671 | |||
612 | set_64bit((u64 *)ptep, native_pte_val(pte)); | 672 | set_64bit((u64 *)ptep, native_pte_val(pte)); |
613 | } | 673 | } |
614 | 674 | ||
@@ -1811,9 +1871,16 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) | |||
1811 | pte = pfn_pte(phys, prot); | 1871 | pte = pfn_pte(phys, prot); |
1812 | break; | 1872 | break; |
1813 | 1873 | ||
1814 | default: | 1874 | case FIX_PARAVIRT_BOOTMAP: |
1875 | /* This is an MFN, but it isn't an IO mapping from the | ||
1876 | IO domain */ | ||
1815 | pte = mfn_pte(phys, prot); | 1877 | pte = mfn_pte(phys, prot); |
1816 | break; | 1878 | break; |
1879 | |||
1880 | default: | ||
1881 | /* By default, set_fixmap is used for hardware mappings */ | ||
1882 | pte = mfn_pte(phys, __pgprot(pgprot_val(prot) | _PAGE_IOMAP)); | ||
1883 | break; | ||
1817 | } | 1884 | } |
1818 | 1885 | ||
1819 | __native_set_fixmap(idx, pte); | 1886 | __native_set_fixmap(idx, pte); |