Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/mm/hap/guest_walk.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * arch/x86/mm/hap/guest_walk.c
3
 *
4
 * Guest page table walker
5
 * Copyright (c) 2007, AMD Corporation (Wei Huang)
6
 * Copyright (c) 2007, XenSource Inc.
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms and conditions of the GNU General Public License,
10
 * version 2, as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope it will be useful, but WITHOUT
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15
 * more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along with
18
 * this program; If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
/* Allow uniquely identifying static symbols in the 3 generated objects. */
22
asm(".file \"" __OBJECT_FILE__ "\"");
23
24
#include <xen/domain_page.h>
25
#include <xen/paging.h>
26
#include <xen/sched.h>
27
#include "private.h" /* for hap_gva_to_gfn_* */
28
29
#define _hap_gva_to_gfn(levels) hap_gva_to_gfn_##levels##_levels
30
#define hap_gva_to_gfn(levels) _hap_gva_to_gfn(levels)
31
32
364k
#define _hap_p2m_ga_to_gfn(levels) hap_p2m_ga_to_gfn_##levels##_levels
33
364k
#define hap_p2m_ga_to_gfn(levels) _hap_p2m_ga_to_gfn(levels)
34
35
#if GUEST_PAGING_LEVELS > CONFIG_PAGING_LEVELS
36
#error GUEST_PAGING_LEVELS must not exceed CONFIG_PAGING_LEVELS
37
#endif
38
39
#include <asm/guest_pt.h>
40
#include <asm/p2m.h>
41
42
unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
43
    struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec)
44
364k
{
45
364k
    unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3];
46
364k
    return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL);
47
364k
}
Unexecuted instantiation: hap_gva_to_gfn_2_levels
Unexecuted instantiation: hap_gva_to_gfn_3_levels
hap_gva_to_gfn_4_levels
Line
Count
Source
44
364k
{
45
364k
    unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3];
46
364k
    return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL);
47
364k
}
48
49
unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(
50
    struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3,
51
    paddr_t ga, uint32_t *pfec, unsigned int *page_order)
52
364k
{
53
364k
    bool walk_ok;
54
364k
    mfn_t top_mfn;
55
364k
    void *top_map;
56
364k
    p2m_type_t p2mt;
57
364k
    walk_t gw;
58
364k
    gfn_t top_gfn;
59
364k
    struct page_info *top_page;
60
364k
61
364k
    /* Get the top-level table's MFN */
62
364k
    top_gfn = _gfn(cr3 >> PAGE_SHIFT);
63
364k
    top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL,
64
364k
                                     P2M_ALLOC | P2M_UNSHARE);
65
364k
    if ( p2m_is_paging(p2mt) )
66
0
    {
67
0
        ASSERT(p2m_is_hostp2m(p2m));
68
0
        *pfec = PFEC_page_paged;
69
0
        if ( top_page )
70
0
            put_page(top_page);
71
0
        p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT);
72
0
        return gfn_x(INVALID_GFN);
73
0
    }
74
364k
    if ( p2m_is_shared(p2mt) )
75
0
    {
76
0
        *pfec = PFEC_page_shared;
77
0
        if ( top_page )
78
0
            put_page(top_page);
79
0
        return gfn_x(INVALID_GFN);
80
0
    }
81
364k
    if ( !top_page )
82
0
    {
83
0
        *pfec &= ~PFEC_page_present;
84
0
        goto out_tweak_pfec;
85
0
    }
86
364k
    top_mfn = _mfn(page_to_mfn(top_page));
87
364k
88
364k
    /* Map the top-level table and call the tree-walker */
89
364k
    ASSERT(mfn_valid(top_mfn));
90
364k
    top_map = map_domain_page(top_mfn);
91
364k
#if GUEST_PAGING_LEVELS == 3
92
0
    top_map += (cr3 & ~(PAGE_MASK | 31));
93
#endif
94
364k
    walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map);
95
364k
    unmap_domain_page(top_map);
96
364k
    put_page(top_page);
97
364k
98
364k
    /* Interpret the answer */
99
364k
    if ( walk_ok )
100
366k
    {
101
366k
        gfn_t gfn = guest_walk_to_gfn(&gw);
102
366k
        struct page_info *page;
103
366k
104
366k
        page = p2m_get_page_from_gfn(p2m, gfn, &p2mt, NULL,
105
366k
                                     P2M_ALLOC | P2M_UNSHARE);
106
366k
        if ( page )
107
366k
            put_page(page);
108
366k
        if ( p2m_is_paging(p2mt) )
109
0
        {
110
0
            ASSERT(p2m_is_hostp2m(p2m));
111
0
            *pfec = PFEC_page_paged;
112
0
            p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
113
0
            return gfn_x(INVALID_GFN);
114
0
        }
115
366k
        if ( p2m_is_shared(p2mt) )
116
0
        {
117
0
            *pfec = PFEC_page_shared;
118
0
            return gfn_x(INVALID_GFN);
119
0
        }
120
366k
121
366k
        if ( page_order )
122
0
            *page_order = guest_walk_to_page_order(&gw);
123
366k
124
366k
        return gfn_x(gfn);
125
366k
    }
126
364k
127
18.4E
    *pfec = gw.pfec;
128
18.4E
129
0
 out_tweak_pfec:
130
0
    /*
131
0
     * SDM Intel 64 Volume 3, Chapter Paging, PAGE-FAULT EXCEPTIONS:
132
0
     * The PFEC_insn_fetch flag is set only when NX or SMEP are enabled.
133
0
     */
134
0
    if ( !hvm_nx_enabled(v) && !hvm_smep_enabled(v) )
135
0
        *pfec &= ~PFEC_insn_fetch;
136
0
137
0
    return gfn_x(INVALID_GFN);
138
18.4E
}
Unexecuted instantiation: hap_p2m_ga_to_gfn_2_levels
Unexecuted instantiation: hap_p2m_ga_to_gfn_3_levels
hap_p2m_ga_to_gfn_4_levels
Line
Count
Source
52
364k
{
53
364k
    bool walk_ok;
54
364k
    mfn_t top_mfn;
55
364k
    void *top_map;
56
364k
    p2m_type_t p2mt;
57
364k
    walk_t gw;
58
364k
    gfn_t top_gfn;
59
364k
    struct page_info *top_page;
60
364k
61
364k
    /* Get the top-level table's MFN */
62
364k
    top_gfn = _gfn(cr3 >> PAGE_SHIFT);
63
364k
    top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL,
64
364k
                                     P2M_ALLOC | P2M_UNSHARE);
65
364k
    if ( p2m_is_paging(p2mt) )
66
0
    {
67
0
        ASSERT(p2m_is_hostp2m(p2m));
68
0
        *pfec = PFEC_page_paged;
69
0
        if ( top_page )
70
0
            put_page(top_page);
71
0
        p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT);
72
0
        return gfn_x(INVALID_GFN);
73
0
    }
74
364k
    if ( p2m_is_shared(p2mt) )
75
0
    {
76
0
        *pfec = PFEC_page_shared;
77
0
        if ( top_page )
78
0
            put_page(top_page);
79
0
        return gfn_x(INVALID_GFN);
80
0
    }
81
364k
    if ( !top_page )
82
0
    {
83
0
        *pfec &= ~PFEC_page_present;
84
0
        goto out_tweak_pfec;
85
0
    }
86
364k
    top_mfn = _mfn(page_to_mfn(top_page));
87
364k
88
364k
    /* Map the top-level table and call the tree-walker */
89
364k
    ASSERT(mfn_valid(top_mfn));
90
364k
    top_map = map_domain_page(top_mfn);
91
364k
#if GUEST_PAGING_LEVELS == 3
92
    top_map += (cr3 & ~(PAGE_MASK | 31));
93
#endif
94
364k
    walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map);
95
364k
    unmap_domain_page(top_map);
96
364k
    put_page(top_page);
97
364k
98
364k
    /* Interpret the answer */
99
364k
    if ( walk_ok )
100
366k
    {
101
366k
        gfn_t gfn = guest_walk_to_gfn(&gw);
102
366k
        struct page_info *page;
103
366k
104
366k
        page = p2m_get_page_from_gfn(p2m, gfn, &p2mt, NULL,
105
366k
                                     P2M_ALLOC | P2M_UNSHARE);
106
366k
        if ( page )
107
366k
            put_page(page);
108
366k
        if ( p2m_is_paging(p2mt) )
109
0
        {
110
0
            ASSERT(p2m_is_hostp2m(p2m));
111
0
            *pfec = PFEC_page_paged;
112
0
            p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
113
0
            return gfn_x(INVALID_GFN);
114
0
        }
115
366k
        if ( p2m_is_shared(p2mt) )
116
0
        {
117
0
            *pfec = PFEC_page_shared;
118
0
            return gfn_x(INVALID_GFN);
119
0
        }
120
366k
121
366k
        if ( page_order )
122
0
            *page_order = guest_walk_to_page_order(&gw);
123
366k
124
366k
        return gfn_x(gfn);
125
366k
    }
126
364k
127
18.4E
    *pfec = gw.pfec;
128
18.4E
129
0
 out_tweak_pfec:
130
0
    /*
131
0
     * SDM Intel 64 Volume 3, Chapter Paging, PAGE-FAULT EXCEPTIONS:
132
0
     * The PFEC_insn_fetch flag is set only when NX or SMEP are enabled.
133
0
     */
134
0
    if ( !hvm_nx_enabled(v) && !hvm_smep_enabled(v) )
135
0
        *pfec &= ~PFEC_insn_fetch;
136
0
137
0
    return gfn_x(INVALID_GFN);
138
18.4E
}
139
140
141
/*
142
 * Local variables:
143
 * mode: C
144
 * c-file-style: "BSD"
145
 * c-basic-offset: 4
146
 * tab-width: 4
147
 * indent-tabs-mode: nil
148
 * End:
149
 */