1183375Skmacy/******************************************************************************
2183375Skmacy * arch-x86/mca.h
3183375Skmacy *
4183375Skmacy * Contributed by Advanced Micro Devices, Inc.
5183375Skmacy * Author: Christoph Egger <Christoph.Egger@amd.com>
6183375Skmacy *
7183375Skmacy * Guest OS machine check interface to x86 Xen.
8183375Skmacy *
9183375Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy
10183375Skmacy * of this software and associated documentation files (the "Software"), to
11183375Skmacy * deal in the Software without restriction, including without limitation the
12183375Skmacy * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13183375Skmacy * sell copies of the Software, and to permit persons to whom the Software is
14183375Skmacy * furnished to do so, subject to the following conditions:
15183375Skmacy *
16183375Skmacy * The above copyright notice and this permission notice shall be included in
17183375Skmacy * all copies or substantial portions of the Software.
18183375Skmacy *
19183375Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20183375Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21183375Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22183375Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23183375Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24183375Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25183375Skmacy * DEALINGS IN THE SOFTWARE.
26183375Skmacy */
27183375Skmacy
28183375Skmacy/* Full MCA functionality has the following Usecases from the guest side:
29183375Skmacy *
30183375Skmacy * Must have's:
31183375Skmacy * 1. Dom0 and DomU register machine check trap callback handlers
32183375Skmacy *    (already done via "set_trap_table" hypercall)
33183375Skmacy * 2. Dom0 registers machine check event callback handler
34183375Skmacy *    (doable via EVTCHNOP_bind_virq)
35183375Skmacy * 3. Dom0 and DomU fetches machine check data
36183375Skmacy * 4. Dom0 wants Xen to notify a DomU
37183375Skmacy * 5. Dom0 gets DomU ID from physical address
38183375Skmacy * 6. Dom0 wants Xen to kill DomU (already done for "xm destroy")
39183375Skmacy *
40183375Skmacy * Nice to have's:
41183375Skmacy * 7. Dom0 wants Xen to deactivate a physical CPU
42183375Skmacy *    This is better done as separate task, physical CPU hotplugging,
43183375Skmacy *    and hypercall(s) should be sysctl's
44183375Skmacy * 8. Page migration proposed from Xen NUMA work, where Dom0 can tell Xen to
45183375Skmacy *    move a DomU (or Dom0 itself) away from a malicious page
46183375Skmacy *    producing correctable errors.
47183375Skmacy * 9. offlining physical page:
48183375Skmacy *    Xen free's and never re-uses a certain physical page.
49183375Skmacy * 10. Testfacility: Allow Dom0 to write values into machine check MSR's
50183375Skmacy *     and tell Xen to trigger a machine check
51183375Skmacy */
52183375Skmacy
53183375Skmacy#ifndef __XEN_PUBLIC_ARCH_X86_MCA_H__
54183375Skmacy#define __XEN_PUBLIC_ARCH_X86_MCA_H__
55183375Skmacy
56183375Skmacy/* Hypercall */
57183375Skmacy#define __HYPERVISOR_mca __HYPERVISOR_arch_0
58183375Skmacy
59183375Skmacy#define XEN_MCA_INTERFACE_VERSION 0x03000001
60183375Skmacy
61183375Skmacy/* IN: Dom0 calls hypercall from MC event handler. */
62183375Skmacy#define XEN_MC_CORRECTABLE  0x0
63183375Skmacy/* IN: Dom0/DomU calls hypercall from MC trap handler. */
64183375Skmacy#define XEN_MC_TRAP         0x1
65183375Skmacy/* XEN_MC_CORRECTABLE and XEN_MC_TRAP are mutually exclusive. */
66183375Skmacy
67183375Skmacy/* OUT: All is ok */
68183375Skmacy#define XEN_MC_OK           0x0
69183375Skmacy/* OUT: Domain could not fetch data. */
70183375Skmacy#define XEN_MC_FETCHFAILED  0x1
71183375Skmacy/* OUT: There was no machine check data to fetch. */
72183375Skmacy#define XEN_MC_NODATA       0x2
73183375Skmacy/* OUT: Between notification time and this hypercall an other
74183375Skmacy *  (most likely) correctable error happened. The fetched data,
75183375Skmacy *  does not match the original machine check data. */
76183375Skmacy#define XEN_MC_NOMATCH      0x4
77183375Skmacy
78183375Skmacy/* OUT: DomU did not register MC NMI handler. Try something else. */
79183375Skmacy#define XEN_MC_CANNOTHANDLE 0x8
80183375Skmacy/* OUT: Notifying DomU failed. Retry later or try something else. */
81183375Skmacy#define XEN_MC_NOTDELIVERED 0x10
82183375Skmacy/* Note, XEN_MC_CANNOTHANDLE and XEN_MC_NOTDELIVERED are mutually exclusive. */
83183375Skmacy
84183375Skmacy
85183375Skmacy#ifndef __ASSEMBLY__
86183375Skmacy
87183375Skmacy#define VIRQ_MCA VIRQ_ARCH_0 /* G. (DOM0) Machine Check Architecture */
88183375Skmacy
89183375Skmacy/*
90183375Skmacy * Machine Check Architecure:
91183375Skmacy * structs are read-only and used to report all kinds of
92183375Skmacy * correctable and uncorrectable errors detected by the HW.
93183375Skmacy * Dom0 and DomU: register a handler to get notified.
94183375Skmacy * Dom0 only: Correctable errors are reported via VIRQ_MCA
95183375Skmacy * Dom0 and DomU: Uncorrectable errors are reported via nmi handlers
96183375Skmacy */
97183375Skmacy#define MC_TYPE_GLOBAL          0
98183375Skmacy#define MC_TYPE_BANK            1
99183375Skmacy#define MC_TYPE_EXTENDED        2
100183375Skmacy
101183375Skmacystruct mcinfo_common {
102183375Skmacy    uint16_t type;      /* structure type */
103183375Skmacy    uint16_t size;      /* size of this struct in bytes */
104183375Skmacy};
105183375Skmacy
106183375Skmacy
107183375Skmacy#define MC_FLAG_CORRECTABLE     (1 << 0)
108183375Skmacy#define MC_FLAG_UNCORRECTABLE   (1 << 1)
109183375Skmacy
110183375Skmacy/* contains global x86 mc information */
111183375Skmacystruct mcinfo_global {
112183375Skmacy    struct mcinfo_common common;
113183375Skmacy
114183375Skmacy    /* running domain at the time in error (most likely the impacted one) */
115183375Skmacy    uint16_t mc_domid;
116183375Skmacy    uint32_t mc_socketid; /* physical socket of the physical core */
117183375Skmacy    uint16_t mc_coreid; /* physical impacted core */
118183375Skmacy    uint16_t mc_core_threadid; /* core thread of physical core */
119183375Skmacy    uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
120183375Skmacy    uint64_t mc_gstatus; /* global status */
121183375Skmacy    uint32_t mc_flags;
122183375Skmacy};
123183375Skmacy
124183375Skmacy/* contains bank local x86 mc information */
125183375Skmacystruct mcinfo_bank {
126183375Skmacy    struct mcinfo_common common;
127183375Skmacy
128183375Skmacy    uint16_t mc_bank; /* bank nr */
129183375Skmacy    uint16_t mc_domid; /* Usecase 5: domain referenced by mc_addr on dom0
130183375Skmacy                        * and if mc_addr is valid. Never valid on DomU. */
131183375Skmacy    uint64_t mc_status; /* bank status */
132183375Skmacy    uint64_t mc_addr;   /* bank address, only valid
133183375Skmacy                         * if addr bit is set in mc_status */
134183375Skmacy    uint64_t mc_misc;
135183375Skmacy};
136183375Skmacy
137183375Skmacy
138183375Skmacystruct mcinfo_msr {
139183375Skmacy    uint64_t reg;   /* MSR */
140183375Skmacy    uint64_t value; /* MSR value */
141183375Skmacy};
142183375Skmacy
143183375Skmacy/* contains mc information from other
144183375Skmacy * or additional mc MSRs */
145183375Skmacystruct mcinfo_extended {
146183375Skmacy    struct mcinfo_common common;
147183375Skmacy
148183375Skmacy    /* You can fill up to five registers.
149183375Skmacy     * If you need more, then use this structure
150183375Skmacy     * multiple times. */
151183375Skmacy
152183375Skmacy    uint32_t mc_msrs; /* Number of msr with valid values. */
153183375Skmacy    struct mcinfo_msr mc_msr[5];
154183375Skmacy};
155183375Skmacy
156183375Skmacy#define MCINFO_HYPERCALLSIZE	1024
157183375Skmacy#define MCINFO_MAXSIZE		768
158183375Skmacy
159183375Skmacystruct mc_info {
160183375Skmacy    /* Number of mcinfo_* entries in mi_data */
161183375Skmacy    uint32_t mi_nentries;
162183375Skmacy
163183375Skmacy    uint8_t mi_data[MCINFO_MAXSIZE - sizeof(uint32_t)];
164183375Skmacy};
165183375Skmacytypedef struct mc_info mc_info_t;
166183375Skmacy
167183375Skmacy
168183375Skmacy
169183375Skmacy/*
170183375Skmacy * OS's should use these instead of writing their own lookup function
171183375Skmacy * each with its own bugs and drawbacks.
172183375Skmacy * We use macros instead of static inline functions to allow guests
173183375Skmacy * to include this header in assembly files (*.S).
174183375Skmacy */
175183375Skmacy/* Prototype:
176183375Skmacy *    uint32_t x86_mcinfo_nentries(struct mc_info *mi);
177183375Skmacy */
178183375Skmacy#define x86_mcinfo_nentries(_mi)    \
179183375Skmacy    (_mi)->mi_nentries
180183375Skmacy/* Prototype:
181183375Skmacy *    struct mcinfo_common *x86_mcinfo_first(struct mc_info *mi);
182183375Skmacy */
183183375Skmacy#define x86_mcinfo_first(_mi)       \
184183375Skmacy    (struct mcinfo_common *)((_mi)->mi_data)
185183375Skmacy/* Prototype:
186183375Skmacy *    struct mcinfo_common *x86_mcinfo_next(struct mcinfo_common *mic);
187183375Skmacy */
188183375Skmacy#define x86_mcinfo_next(_mic)       \
189183375Skmacy    (struct mcinfo_common *)((uint8_t *)(_mic) + (_mic)->size)
190183375Skmacy
191183375Skmacy/* Prototype:
192183375Skmacy *    void x86_mcinfo_lookup(void *ret, struct mc_info *mi, uint16_t type);
193183375Skmacy */
194183375Skmacy#define x86_mcinfo_lookup(_ret, _mi, _type)    \
195183375Skmacy    do {                                                        \
196183375Skmacy        uint32_t found, i;                                      \
197183375Skmacy        struct mcinfo_common *_mic;                             \
198183375Skmacy                                                                \
199183375Skmacy        found = 0;                                              \
200183375Skmacy	(_ret) = NULL;						\
201183375Skmacy	if (_mi == NULL) break;					\
202183375Skmacy        _mic = x86_mcinfo_first(_mi);                           \
203183375Skmacy        for (i = 0; i < x86_mcinfo_nentries(_mi); i++) {        \
204183375Skmacy            if (_mic->type == (_type)) {                        \
205183375Skmacy                found = 1;                                      \
206183375Skmacy                break;                                          \
207183375Skmacy            }                                                   \
208183375Skmacy            _mic = x86_mcinfo_next(_mic);                       \
209183375Skmacy        }                                                       \
210183375Skmacy        (_ret) = found ? _mic : NULL;                           \
211183375Skmacy    } while (0)
212183375Skmacy
213183375Skmacy
214183375Skmacy/* Usecase 1
215183375Skmacy * Register machine check trap callback handler
216183375Skmacy *    (already done via "set_trap_table" hypercall)
217183375Skmacy */
218183375Skmacy
219183375Skmacy/* Usecase 2
220183375Skmacy * Dom0 registers machine check event callback handler
221183375Skmacy * done by EVTCHNOP_bind_virq
222183375Skmacy */
223183375Skmacy
224183375Skmacy/* Usecase 3
225183375Skmacy * Fetch machine check data from hypervisor.
226183375Skmacy * Note, this hypercall is special, because both Dom0 and DomU must use this.
227183375Skmacy */
228183375Skmacy#define XEN_MC_fetch            1
229183375Skmacystruct xen_mc_fetch {
230183375Skmacy    /* IN/OUT variables. */
231183375Skmacy    uint32_t flags;
232183375Skmacy
233183375Skmacy/* IN: XEN_MC_CORRECTABLE, XEN_MC_TRAP */
234183375Skmacy/* OUT: XEN_MC_OK, XEN_MC_FETCHFAILED, XEN_MC_NODATA, XEN_MC_NOMATCH */
235183375Skmacy
236183375Skmacy    /* OUT variables. */
237183375Skmacy    uint32_t fetch_idx;  /* only useful for Dom0 for the notify hypercall */
238183375Skmacy    struct mc_info mc_info;
239183375Skmacy};
240183375Skmacytypedef struct xen_mc_fetch xen_mc_fetch_t;
241183375SkmacyDEFINE_XEN_GUEST_HANDLE(xen_mc_fetch_t);
242183375Skmacy
243183375Skmacy
244183375Skmacy/* Usecase 4
245183375Skmacy * This tells the hypervisor to notify a DomU about the machine check error
246183375Skmacy */
247183375Skmacy#define XEN_MC_notifydomain     2
248183375Skmacystruct xen_mc_notifydomain {
249183375Skmacy    /* IN variables. */
250183375Skmacy    uint16_t mc_domid;    /* The unprivileged domain to notify. */
251183375Skmacy    uint16_t mc_vcpuid;   /* The vcpu in mc_domid to notify.
252183375Skmacy                           * Usually echo'd value from the fetch hypercall. */
253183375Skmacy    uint32_t fetch_idx;   /* echo'd value from the fetch hypercall. */
254183375Skmacy
255183375Skmacy    /* IN/OUT variables. */
256183375Skmacy    uint32_t flags;
257183375Skmacy
258183375Skmacy/* IN: XEN_MC_CORRECTABLE, XEN_MC_TRAP */
259183375Skmacy/* OUT: XEN_MC_OK, XEN_MC_CANNOTHANDLE, XEN_MC_NOTDELIVERED, XEN_MC_NOMATCH */
260183375Skmacy};
261183375Skmacytypedef struct xen_mc_notifydomain xen_mc_notifydomain_t;
262183375SkmacyDEFINE_XEN_GUEST_HANDLE(xen_mc_notifydomain_t);
263183375Skmacy
264183375Skmacy
265183375Skmacystruct xen_mc {
266183375Skmacy    uint32_t cmd;
267183375Skmacy    uint32_t interface_version; /* XEN_MCA_INTERFACE_VERSION */
268183375Skmacy    union {
269183375Skmacy        struct xen_mc_fetch        mc_fetch;
270183375Skmacy        struct xen_mc_notifydomain mc_notifydomain;
271183375Skmacy        uint8_t pad[MCINFO_HYPERCALLSIZE];
272183375Skmacy    } u;
273183375Skmacy};
274183375Skmacytypedef struct xen_mc xen_mc_t;
275183375SkmacyDEFINE_XEN_GUEST_HANDLE(xen_mc_t);
276183375Skmacy
277183375Skmacy#endif /* __ASSEMBLY__ */
278183375Skmacy
279183375Skmacy#endif /* __XEN_PUBLIC_ARCH_X86_MCA_H__ */
280