| 1 |
|
| 2 | |
| 3 | * arch-x86/mca.h
|
| 4 | * Guest OS machine check interface to x86 Xen.
|
| 5 | *
|
| 6 | * Contributed by Advanced Micro Devices, Inc.
|
| 7 | * Author: Christoph Egger <[email protected]>
|
| 8 | *
|
| 9 | * Updated by Intel Corporation
|
| 10 | * Author: Liu, Jinsong <[email protected]>
|
| 11 | *
|
| 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 13 | * of this software and associated documentation files (the "Software"), to
|
| 14 | * deal in the Software without restriction, including without limitation the
|
| 15 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 16 | * sell copies of the Software, and to permit persons to whom the Software is
|
| 17 | * furnished to do so, subject to the following conditions:
|
| 18 | *
|
| 19 | * The above copyright notice and this permission notice shall be included in
|
| 20 | * all copies or substantial portions of the Software.
|
| 21 | *
|
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
| 28 | * DEALINGS IN THE SOFTWARE.
|
| 29 |
|
| 30 |
|
| 31 | #ifndef __XEN_PUBLIC_ARCH_X86_MCA_H__
|
| 32 | #define __XEN_PUBLIC_ARCH_X86_MCA_H__
|
| 33 |
|
| 34 |
|
| 35 | #define __HYPERVISOR_mca __HYPERVISOR_arch_0
|
| 36 |
|
| 37 | #define XEN_MCA_INTERFACE_VERSION 0x01ecc003
|
| 38 |
|
| 39 |
|
| 40 | #define XEN_MC_NONURGENT 0x1
|
| 41 |
|
| 42 | #define XEN_MC_URGENT 0x2
|
| 43 |
|
| 44 | #define XEN_MC_ACK 0x4
|
| 45 |
|
| 46 |
|
| 47 | #define XEN_MC_OK 0x0
|
| 48 |
|
| 49 | #define XEN_MC_FETCHFAILED 0x1
|
| 50 |
|
| 51 | #define XEN_MC_NODATA 0x2
|
| 52 |
|
| 53 | #ifndef __ASSEMBLER__
|
| 54 |
|
| 55 | #define VIRQ_MCA VIRQ_ARCH_0
|
| 56 |
|
| 57 | |
| 58 | * mc_info entry types
|
| 59 | * mca machine check info are recorded in mc_info entries.
|
| 60 | * when fetch mca info, it can use MC_TYPE_... to distinguish
|
| 61 | * different mca info.
|
| 62 |
|
| 63 | #define MC_TYPE_GLOBAL 0
|
| 64 | #define MC_TYPE_BANK 1
|
| 65 | #define MC_TYPE_EXTENDED 2
|
| 66 | #define MC_TYPE_RECOVERY 3
|
| 67 |
|
| 68 | struct mcinfo_common {
|
| 69 | uint16_t type;
|
| 70 | uint16_t size;
|
| 71 | };
|
| 72 |
|
| 73 | #define MC_FLAG_CORRECTABLE (1 << 0)
|
| 74 | #define MC_FLAG_UNCORRECTABLE (1 << 1)
|
| 75 | #define MC_FLAG_RECOVERABLE (1 << 2)
|
| 76 | #define MC_FLAG_POLLED (1 << 3)
|
| 77 | #define MC_FLAG_RESET (1 << 4)
|
| 78 | #define MC_FLAG_CMCI (1 << 5)
|
| 79 | #define MC_FLAG_MCE (1 << 6)
|
| 80 |
|
| 81 |
|
| 82 | struct mcinfo_global {
|
| 83 | struct mcinfo_common common;
|
| 84 |
|
| 85 | uint16_t mc_domid;
|
| 86 | uint16_t mc_vcpuid;
|
| 87 | uint32_t mc_socketid;
|
| 88 | uint16_t mc_coreid;
|
| 89 | uint16_t mc_core_threadid;
|
| 90 | uint32_t mc_apicid;
|
| 91 | uint32_t mc_flags;
|
| 92 | uint64_t mc_gstatus;
|
| 93 | };
|
| 94 |
|
| 95 |
|
| 96 | struct mcinfo_bank {
|
| 97 | struct mcinfo_common common;
|
| 98 |
|
| 99 | uint16_t mc_bank;
|
| 100 | uint16_t mc_domid;
|
| 101 | uint64_t mc_status;
|
| 102 | uint64_t mc_addr;
|
| 103 | uint64_t mc_misc;
|
| 104 | uint64_t mc_ctrl2;
|
| 105 | uint64_t mc_tsc;
|
| 106 | };
|
| 107 |
|
| 108 | struct mcinfo_msr {
|
| 109 | uint64_t reg;
|
| 110 | uint64_t value;
|
| 111 | };
|
| 112 |
|
| 113 |
|
| 114 | struct mcinfo_extended {
|
| 115 | struct mcinfo_common common;
|
| 116 | uint32_t mc_msrs;
|
| 117 | |
| 118 | * Currently Intel extended MSR (32/64) include all gp registers
|
| 119 | * and E(R)FLAGS, E(R)IP, E(R)MISC, up to 11/19 of them might be
|
| 120 | * useful at present. So expand this array to 16/32 to leave room.
|
| 121 |
|
| 122 | struct mcinfo_msr mc_msr[sizeof(void *) * 4];
|
| 123 | };
|
| 124 |
|
| 125 |
|
| 126 |
|
| 127 |
|
| 128 | #define REC_ACTION_RECOVERED (0x1 << 0)
|
| 129 |
|
| 130 | #define REC_ACTION_NONE (0x1 << 1)
|
| 131 |
|
| 132 | #define REC_ACTION_NEED_RESET (0x1 << 2)
|
| 133 |
|
| 134 | |
| 135 | * Different Recovery Action types, if the action is performed successfully,
|
| 136 | * REC_ACTION_RECOVERED flag will be returned.
|
| 137 |
|
| 138 |
|
| 139 |
|
| 140 | #define MC_ACTION_PAGE_OFFLINE (0x1 << 0)
|
| 141 |
|
| 142 | #define MC_ACTION_CPU_OFFLINE (0x1 << 1)
|
| 143 |
|
| 144 | #define MC_ACTION_CACHE_SHRINK (0x1 << 2)
|
| 145 |
|
| 146 | |
| 147 | * Below interface used between XEN/DOM0 for passing XEN's recovery action
|
| 148 | * information to DOM0.
|
| 149 |
|
| 150 | struct page_offline_action {
|
| 151 |
|
| 152 | uint64_t mfn;
|
| 153 | uint64_t status;
|
| 154 | };
|
| 155 |
|
| 156 | struct cpu_offline_action {
|
| 157 |
|
| 158 | uint32_t mc_socketid;
|
| 159 | uint16_t mc_coreid;
|
| 160 | uint16_t mc_core_threadid;
|
| 161 | };
|
| 162 |
|
| 163 | #define MAX_UNION_SIZE 16
|
| 164 | struct mcinfo_recovery {
|
| 165 | struct mcinfo_common common;
|
| 166 | uint16_t mc_bank;
|
| 167 | uint8_t action_flags;
|
| 168 | uint8_t action_types;
|
| 169 | union {
|
| 170 | struct page_offline_action page_retire;
|
| 171 | struct cpu_offline_action cpu_offline;
|
| 172 | uint8_t pad[MAX_UNION_SIZE];
|
| 173 | } action_info;
|
| 174 | };
|
| 175 |
|
| 176 |
|
| 177 | #define MCINFO_MAXSIZE 768
|
| 178 | struct mc_info {
|
| 179 |
|
| 180 | uint32_t mi_nentries;
|
| 181 | uint32_t flags;
|
| 182 | uint64_t mi_data[(MCINFO_MAXSIZE - 1) / 8];
|
| 183 | };
|
| 184 | DEFINE_GUEST_HANDLE_STRUCT(mc_info);
|
| 185 |
|
| 186 | #define __MC_MSR_ARRAYSIZE 8
|
| 187 | #define __MC_NMSRS 1
|
| 188 | #define MC_NCAPS 7
|
| 189 | struct mcinfo_logical_cpu {
|
| 190 | uint32_t mc_cpunr;
|
| 191 | uint32_t mc_chipid;
|
| 192 | uint16_t mc_coreid;
|
| 193 | uint16_t mc_threadid;
|
| 194 | uint32_t mc_apicid;
|
| 195 | uint32_t mc_clusterid;
|
| 196 | uint32_t mc_ncores;
|
| 197 | uint32_t mc_ncores_active;
|
| 198 | uint32_t mc_nthreads;
|
| 199 | uint32_t mc_cpuid_level;
|
| 200 | uint32_t mc_family;
|
| 201 | uint32_t mc_vendor;
|
| 202 | uint32_t mc_model;
|
| 203 | uint32_t mc_step;
|
| 204 | char mc_vendorid[16];
|
| 205 | char mc_brandid[64];
|
| 206 | uint32_t mc_cpu_caps[MC_NCAPS];
|
| 207 | uint32_t mc_cache_size;
|
| 208 | uint32_t mc_cache_alignment;
|
| 209 | uint32_t mc_nmsrvals;
|
| 210 | struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
|
| 211 | };
|
| 212 | DEFINE_GUEST_HANDLE_STRUCT(mcinfo_logical_cpu);
|
| 213 |
|
| 214 | |
| 215 | * Prototype:
|
| 216 | * uint32_t x86_mcinfo_nentries(struct mc_info *mi);
|
| 217 |
|
| 218 | #define x86_mcinfo_nentries(_mi) \
|
| 219 | ((_mi)->mi_nentries)
|
| 220 | |
| 221 | * Prototype:
|
| 222 | * struct mcinfo_common *x86_mcinfo_first(struct mc_info *mi);
|
| 223 |
|
| 224 | #define x86_mcinfo_first(_mi) \
|
| 225 | ((struct mcinfo_common *)(_mi)->mi_data)
|
| 226 | |
| 227 | * Prototype:
|
| 228 | * struct mcinfo_common *x86_mcinfo_next(struct mcinfo_common *mic);
|
| 229 |
|
| 230 | #define x86_mcinfo_next(_mic) \
|
| 231 | ((struct mcinfo_common *)((uint8_t *)(_mic) + (_mic)->size))
|
| 232 |
|
| 233 | |
| 234 | * Prototype:
|
| 235 | * void x86_mcinfo_lookup(void *ret, struct mc_info *mi, uint16_t type);
|
| 236 |
|
| 237 | static inline void x86_mcinfo_lookup(struct mcinfo_common **ret,
|
| 238 | struct mc_info *mi, uint16_t type)
|
| 239 | {
|
| 240 | uint32_t i;
|
| 241 | struct mcinfo_common *mic;
|
| 242 | bool found = 0;
|
| 243 |
|
| 244 | if (!ret || !mi)
|
| 245 | return;
|
| 246 |
|
| 247 | mic = x86_mcinfo_first(mi);
|
| 248 | for (i = 0; i < x86_mcinfo_nentries(mi); i++) {
|
| 249 | if (mic->type == type) {
|
| 250 | found = 1;
|
| 251 | break;
|
| 252 | }
|
| 253 | mic = x86_mcinfo_next(mic);
|
| 254 | }
|
| 255 |
|
| 256 | *ret = found ? mic : NULL;
|
| 257 | }
|
| 258 |
|
| 259 | |
| 260 | * Fetch machine check data from hypervisor.
|
| 261 |
|
| 262 | #define XEN_MC_fetch 1
|
| 263 | struct xen_mc_fetch {
|
| 264 | |
| 265 | * IN: XEN_MC_NONURGENT, XEN_MC_URGENT,
|
| 266 | * XEN_MC_ACK if ack'king an earlier fetch
|
| 267 | * OUT: XEN_MC_OK, XEN_MC_FETCHAILED, XEN_MC_NODATA
|
| 268 |
|
| 269 | uint32_t flags;
|
| 270 | uint32_t _pad0;
|
| 271 |
|
| 272 | uint64_t fetch_id;
|
| 273 |
|
| 274 |
|
| 275 | GUEST_HANDLE(mc_info) data;
|
| 276 | };
|
| 277 | DEFINE_GUEST_HANDLE_STRUCT(xen_mc_fetch);
|
| 278 |
|
| 279 |
|
| 280 | |
| 281 | * This tells the hypervisor to notify a DomU about the machine check error
|
| 282 |
|
| 283 | #define XEN_MC_notifydomain 2
|
| 284 | struct xen_mc_notifydomain {
|
| 285 |
|
| 286 | uint16_t mc_domid;
|
| 287 | uint16_t mc_vcpuid;
|
| 288 |
|
| 289 |
|
| 290 | uint32_t flags;
|
| 291 | };
|
| 292 | DEFINE_GUEST_HANDLE_STRUCT(xen_mc_notifydomain);
|
| 293 |
|
| 294 | #define XEN_MC_physcpuinfo 3
|
| 295 | struct xen_mc_physcpuinfo {
|
| 296 |
|
| 297 | uint32_t ncpus;
|
| 298 | uint32_t _pad0;
|
| 299 |
|
| 300 | GUEST_HANDLE(mcinfo_logical_cpu) info;
|
| 301 | };
|
| 302 |
|
| 303 | #define XEN_MC_msrinject 4
|
| 304 | #define MC_MSRINJ_MAXMSRS 8
|
| 305 | struct xen_mc_msrinject {
|
| 306 |
|
| 307 | uint32_t mcinj_cpunr;
|
| 308 | uint32_t mcinj_flags;
|
| 309 | uint32_t mcinj_count;
|
| 310 | uint32_t _pad0;
|
| 311 | struct mcinfo_msr mcinj_msr[MC_MSRINJ_MAXMSRS];
|
| 312 | };
|
| 313 |
|
| 314 |
|
| 315 | #define MC_MSRINJ_F_INTERPOSE 0x1
|
| 316 |
|
| 317 | #define XEN_MC_mceinject 5
|
| 318 | struct xen_mc_mceinject {
|
| 319 | unsigned int mceinj_cpunr;
|
| 320 | };
|
| 321 |
|
| 322 | struct xen_mc {
|
| 323 | uint32_t cmd;
|
| 324 | uint32_t interface_version;
|
| 325 | union {
|
| 326 | struct xen_mc_fetch mc_fetch;
|
| 327 | struct xen_mc_notifydomain mc_notifydomain;
|
| 328 | struct xen_mc_physcpuinfo mc_physcpuinfo;
|
| 329 | struct xen_mc_msrinject mc_msrinject;
|
| 330 | struct xen_mc_mceinject mc_mceinject;
|
| 331 | } u;
|
| 332 | };
|
| 333 | DEFINE_GUEST_HANDLE_STRUCT(xen_mc);
|
| 334 |
|
| 335 | |
| 336 | * Fields are zero when not available. Also, this struct is shared with
|
| 337 | * userspace mcelog and thus must keep existing fields at current offsets.
|
| 338 | * Only add new fields to the end of the structure
|
| 339 |
|
| 340 | struct xen_mce {
|
| 341 | __u64 status;
|
| 342 | __u64 misc;
|
| 343 | __u64 addr;
|
| 344 | __u64 mcgstatus;
|
| 345 | __u64 ip;
|
| 346 | __u64 tsc;
|
| 347 | __u64 time;
|
| 348 | __u8 cpuvendor;
|
| 349 | __u8 inject_flags;
|
| 350 | __u16 pad;
|
| 351 | __u32 cpuid;
|
| 352 | __u8 cs;
|
| 353 | __u8 bank;
|
| 354 | __u8 cpu;
|
| 355 | __u8 finished;
|
| 356 | __u32 extcpu;
|
| 357 | __u32 socketid;
|
| 358 | __u32 apicid;
|
| 359 | __u64 mcgcap;
|
| 360 | __u64 synd;
|
| 361 | __u64 ipid;
|
| 362 | __u64 ppin;
|
| 363 | };
|
| 364 |
|
| 365 | |
| 366 | * This structure contains all data related to the MCE log. Also
|
| 367 | * carries a signature to make it easier to find from external
|
| 368 | * debugging tools. Each entry is only valid when its finished flag
|
| 369 | * is set.
|
| 370 |
|
| 371 |
|
| 372 | #define XEN_MCE_LOG_LEN 32
|
| 373 |
|
| 374 | struct xen_mce_log {
|
| 375 | char signature[12] __nonstring;
|
| 376 | unsigned len;
|
| 377 | unsigned next;
|
| 378 | unsigned flags;
|
| 379 | unsigned recordlen;
|
| 380 | struct xen_mce entry[XEN_MCE_LOG_LEN];
|
| 381 | };
|
| 382 |
|
| 383 | #define XEN_MCE_OVERFLOW 0
|
| 384 |
|
| 385 | #define XEN_MCE_LOG_SIGNATURE "MACHINECHECK"
|
| 386 |
|
| 387 | #define MCE_GET_RECORD_LEN _IOR('M', 1, int)
|
| 388 | #define MCE_GET_LOG_LEN _IOR('M', 2, int)
|
| 389 | #define MCE_GETCLEAR_FLAGS _IOR('M', 3, int)
|
| 390 |
|
| 391 | #endif
|
| 392 | #endif
|