1 /******************************************************************************
2  * xc_pagetab.c
3  *
4  * Function to translate virtual to physical addresses.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation;
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "xc_private.h"
21 #include <xen/hvm/save.h>
22 
23 #define CR0_PG  0x80000000
24 #define CR4_PAE 0x20
25 #define PTE_PSE 0x80
26 #define EFER_LMA 0x400
27 
28 
xc_translate_foreign_address(xc_interface * xch,uint32_t dom,int vcpu,unsigned long long virt)29 unsigned long xc_translate_foreign_address(xc_interface *xch, uint32_t dom,
30                                            int vcpu, unsigned long long virt)
31 {
32     xc_dominfo_t dominfo;
33     uint64_t paddr, mask, pte = 0;
34     int size, level, pt_levels = 2;
35     void *map;
36 
37     if (xc_domain_getinfo(xch, dom, 1, &dominfo) != 1
38         || dominfo.domid != dom)
39         return 0;
40 
41     /* What kind of paging are we dealing with? */
42     if (dominfo.hvm) {
43         struct hvm_hw_cpu ctx;
44         if (xc_domain_hvm_getcontext_partial(xch, dom,
45                                              HVM_SAVE_CODE(CPU), vcpu,
46                                              &ctx, sizeof ctx) != 0)
47             return 0;
48         if (!(ctx.cr0 & CR0_PG))
49             return virt >> PAGE_SHIFT;
50         pt_levels = (ctx.msr_efer&EFER_LMA) ? 4 : (ctx.cr4&CR4_PAE) ? 3 : 2;
51         paddr = ctx.cr3 & ((pt_levels == 3) ? ~0x1full : ~0xfffull);
52     } else {
53         unsigned int gwidth;
54         vcpu_guest_context_any_t ctx;
55         if (xc_vcpu_getcontext(xch, dom, vcpu, &ctx) != 0)
56             return 0;
57         if (xc_domain_get_guest_width(xch, dom, &gwidth) != 0)
58             return 0;
59         if (gwidth == 8) {
60             pt_levels = 4;
61             paddr = (uint64_t)xen_cr3_to_pfn_x86_64(ctx.x64.ctrlreg[3])
62                 << PAGE_SHIFT;
63         } else {
64             pt_levels = 3;
65             paddr = (uint64_t)xen_cr3_to_pfn_x86_32(ctx.x32.ctrlreg[3])
66                 << PAGE_SHIFT;
67         }
68     }
69 
70     if (pt_levels == 4) {
71         virt &= 0x0000ffffffffffffull;
72         mask =  0x0000ff8000000000ull;
73     } else if (pt_levels == 3) {
74         virt &= 0x00000000ffffffffull;
75         mask =  0x0000007fc0000000ull;
76     } else {
77         virt &= 0x00000000ffffffffull;
78         mask =  0x00000000ffc00000ull;
79     }
80     size = (pt_levels == 2 ? 4 : 8);
81 
82     /* Walk the pagetables */
83     for (level = pt_levels; level > 0; level--) {
84         paddr += ((virt & mask) >> (xc_ffs64(mask) - 1)) * size;
85         map = xc_map_foreign_range(xch, dom, PAGE_SIZE, PROT_READ,
86                                    paddr >>PAGE_SHIFT);
87         if (!map)
88             return 0;
89         memcpy(&pte, map + (paddr & (PAGE_SIZE - 1)), size);
90         munmap(map, PAGE_SIZE);
91         if (!(pte & 1)) {
92             errno = EADDRNOTAVAIL;
93             return 0;
94         }
95         paddr = pte & 0x000ffffffffff000ull;
96         if ((level == 2 || (level == 3 && pt_levels == 4)) && (pte & PTE_PSE)) {
97             mask = ((mask ^ ~-mask) >> 1); /* All bits below first set bit */
98             return ((paddr & ~mask) | (virt & mask)) >> PAGE_SHIFT;
99         }
100         mask >>= (pt_levels == 2 ? 10 : 9);
101     }
102     return paddr >> PAGE_SHIFT;
103 }
104 
105 /*
106  * Local variables:
107  * mode: C
108  * c-file-style: "BSD"
109  * c-basic-offset: 4
110  * tab-width: 4
111  * indent-tabs-mode: nil
112  * End:
113  */
114