Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/cpu/mcheck/mcaction.c
Line
Count
Source (jump to first uncovered line)
1
#include <xen/types.h>
2
#include <xen/sched.h>
3
#include "mcaction.h"
4
#include "vmce.h"
5
#include "mce.h"
6
7
static struct mcinfo_recovery *
8
mci_action_add_pageoffline(int bank, struct mc_info *mi,
9
                           uint64_t mfn, uint32_t status)
10
0
{
11
0
    struct mcinfo_recovery *rec;
12
0
13
0
    if ( !mi )
14
0
        return NULL;
15
0
16
0
    rec = x86_mcinfo_reserve(mi, sizeof(*rec), MC_TYPE_RECOVERY);
17
0
    if ( !rec )
18
0
    {
19
0
        mi->flags |= MCINFO_FLAGS_UNCOMPLETE;
20
0
        return NULL;
21
0
    }
22
0
23
0
    rec->mc_bank = bank;
24
0
    rec->action_types = MC_ACTION_PAGE_OFFLINE;
25
0
    rec->action_info.page_retire.mfn = mfn;
26
0
    rec->action_info.page_retire.status = status;
27
0
    return rec;
28
0
}
29
30
mce_check_addr_t mc_check_addr = NULL;
31
32
void mce_register_addrcheck(mce_check_addr_t cbfunc)
33
12
{
34
12
    mc_check_addr = cbfunc;
35
12
}
36
37
void
38
mc_memerr_dhandler(struct mca_binfo *binfo,
39
                   enum mce_result *result,
40
                   const struct cpu_user_regs *regs)
41
0
{
42
0
    struct mcinfo_bank *bank = binfo->mib;
43
0
    struct mcinfo_global *global = binfo->mig;
44
0
    struct domain *d;
45
0
    unsigned long mfn, gfn;
46
0
    uint32_t status;
47
0
    int vmce_vcpuid;
48
0
    unsigned int mc_vcpuid;
49
0
50
0
    if ( !mc_check_addr(bank->mc_status, bank->mc_misc, MC_ADDR_PHYSICAL) )
51
0
    {
52
0
        dprintk(XENLOG_WARNING,
53
0
                "No physical address provided for memory error\n");
54
0
        return;
55
0
    }
56
0
57
0
    mfn = bank->mc_addr >> PAGE_SHIFT;
58
0
    if ( offline_page(mfn, 1, &status) )
59
0
    {
60
0
        dprintk(XENLOG_WARNING,
61
0
                "Failed to offline page %lx for MCE error\n", mfn);
62
0
        return;
63
0
    }
64
0
65
0
    mci_action_add_pageoffline(binfo->bank, binfo->mi, mfn, status);
66
0
67
0
    /* This is free page */
68
0
    if ( status & PG_OFFLINE_OFFLINED )
69
0
        *result = MCER_RECOVERED;
70
0
    else if ( status & PG_OFFLINE_AGAIN )
71
0
        *result = MCER_CONTINUE;
72
0
    else if ( status & PG_OFFLINE_PENDING )
73
0
    {
74
0
        /* This page has owner */
75
0
        if ( status & PG_OFFLINE_OWNED )
76
0
        {
77
0
            bank->mc_domid = status >> PG_OFFLINE_OWNER_SHIFT;
78
0
            mce_printk(MCE_QUIET, "MCE: This error page is ownded"
79
0
                       " by DOM %d\n", bank->mc_domid);
80
0
            /*
81
0
             * XXX: Cannot handle shared pages yet
82
0
             * (this should identify all domains and gfn mapping to
83
0
             *  the mfn in question)
84
0
             */
85
0
            BUG_ON( bank->mc_domid == DOMID_COW );
86
0
            if ( bank->mc_domid != DOMID_XEN )
87
0
            {
88
0
                d = get_domain_by_id(bank->mc_domid);
89
0
                ASSERT(d);
90
0
                gfn = get_gpfn_from_mfn((bank->mc_addr) >> PAGE_SHIFT);
91
0
92
0
                if ( unmmap_broken_page(d, _mfn(mfn), gfn) )
93
0
                {
94
0
                    printk("Unmap broken memory %lx for DOM%d failed\n",
95
0
                           mfn, d->domain_id);
96
0
                    goto vmce_failed;
97
0
                }
98
0
99
0
                mc_vcpuid = global->mc_vcpuid;
100
0
                if ( mc_vcpuid == XEN_MC_VCPUID_INVALID ||
101
0
                     /*
102
0
                      * Because MC# may happen asynchronously with the actual
103
0
                      * operation that triggers the error, the domain ID as
104
0
                      * well as the vCPU ID collected in 'global' at MC# are
105
0
                      * not always precise. In that case, fallback to broadcast.
106
0
                      */
107
0
                     global->mc_domid != bank->mc_domid ||
108
0
                     (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
109
0
                      (!(global->mc_gstatus & MCG_STATUS_LMCE) ||
110
0
                       !(d->vcpu[mc_vcpuid]->arch.vmce.mcg_ext_ctl &
111
0
                         MCG_EXT_CTL_LMCE_EN))) )
112
0
                    vmce_vcpuid = VMCE_INJECT_BROADCAST;
113
0
                else
114
0
                    vmce_vcpuid = mc_vcpuid;
115
0
116
0
                bank->mc_addr = gfn << PAGE_SHIFT |
117
0
                                (bank->mc_addr & (PAGE_SIZE - 1));
118
0
                if ( fill_vmsr_data(bank, d, global->mc_gstatus, vmce_vcpuid) )
119
0
                {
120
0
                    mce_printk(MCE_QUIET, "Fill vMCE# data for DOM%d "
121
0
                               "failed\n", bank->mc_domid);
122
0
                    goto vmce_failed;
123
0
                }
124
0
125
0
                /* We will inject vMCE to DOMU */
126
0
                if ( inject_vmce(d, vmce_vcpuid) < 0 )
127
0
                {
128
0
                    mce_printk(MCE_QUIET, "inject vMCE to DOM%d"
129
0
                               " failed\n", d->domain_id);
130
0
                    goto vmce_failed;
131
0
                }
132
0
133
0
                /*
134
0
                 * Impacted domain go on with domain's recovery job
135
0
                 * if the domain has its own MCA handler.
136
0
                 * For xen, it has contained the error and finished
137
0
                 * its own recovery job.
138
0
                 */
139
0
                *result = MCER_RECOVERED;
140
0
                put_domain(d);
141
0
142
0
                return;
143
0
vmce_failed:
144
0
                put_domain(d);
145
0
                domain_crash(d);
146
0
            }
147
0
        }
148
0
    }
149
0
}