forked from Minki/linux
d2a28ad9fa
Memory errors encountered by user applications may surface when the CPU is running in kernel context. The current code will not attempt recovery if the MCA surfaces in kernel context (privilage mode 0). This patch adds a check for cases where the user initiated the load that surfaces in kernel interrupt code. An example is a user process lauching a load from memory and the data in memory had bad ECC. Before the bad data gets to the CPU register, and interrupt comes in. The code jumps to the IVT interrupt entry point and begins execution in kernel context. The process of saving the user registers (SAVE_REST) causes the bad data to be loaded into a CPU register, triggering the MCA. The MCA surfaces in kernel context, even though the load was initiated from user context. As suggested by David and Tony, this patch uses an exception table like approach, puting the tagged recovery addresses in a searchable table. One difference from the exception table is that MCAs do not surface in precise places (such as with a TLB miss), so instead of tagging specific instructions, address ranges are registers. A single macro is used to do the tagging, with the input parameter being the label of the starting address and the macro being the ending address. This limits clutter in the code. This patch only tags one spot, the interrupt ivt entry. Testing showed that spot to be a "heavy hitter" with MCAs surfacing while saving user registers. Other spots can be added as needed by adding a single macro. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck <tony.luck@intel.com>
123 lines
2.8 KiB
C
123 lines
2.8 KiB
C
#ifndef _ASM_IA64_ASMMACRO_H
|
|
#define _ASM_IA64_ASMMACRO_H
|
|
|
|
/*
|
|
* Copyright (C) 2000-2001, 2003-2004 Hewlett-Packard Co
|
|
* David Mosberger-Tang <davidm@hpl.hp.com>
|
|
*/
|
|
|
|
#include <linux/config.h>
|
|
|
|
#define ENTRY(name) \
|
|
.align 32; \
|
|
.proc name; \
|
|
name:
|
|
|
|
#define ENTRY_MIN_ALIGN(name) \
|
|
.align 16; \
|
|
.proc name; \
|
|
name:
|
|
|
|
#define GLOBAL_ENTRY(name) \
|
|
.global name; \
|
|
ENTRY(name)
|
|
|
|
#define END(name) \
|
|
.endp name
|
|
|
|
/*
|
|
* Helper macros to make unwind directives more readable:
|
|
*/
|
|
|
|
/* prologue_gr: */
|
|
#define ASM_UNW_PRLG_RP 0x8
|
|
#define ASM_UNW_PRLG_PFS 0x4
|
|
#define ASM_UNW_PRLG_PSP 0x2
|
|
#define ASM_UNW_PRLG_PR 0x1
|
|
#define ASM_UNW_PRLG_GRSAVE(ninputs) (32+(ninputs))
|
|
|
|
/*
|
|
* Helper macros for accessing user memory.
|
|
*/
|
|
|
|
.section "__ex_table", "a" // declare section & section attributes
|
|
.previous
|
|
|
|
# define EX(y,x...) \
|
|
.xdata4 "__ex_table", 99f-., y-.; \
|
|
[99:] x
|
|
# define EXCLR(y,x...) \
|
|
.xdata4 "__ex_table", 99f-., y-.+4; \
|
|
[99:] x
|
|
|
|
/*
|
|
* Tag MCA recoverable instruction ranges.
|
|
*/
|
|
|
|
.section "__mca_table", "a" // declare section & section attributes
|
|
.previous
|
|
|
|
# define MCA_RECOVER_RANGE(y) \
|
|
.xdata4 "__mca_table", y-., 99f-.; \
|
|
[99:]
|
|
|
|
/*
|
|
* Mark instructions that need a load of a virtual address patched to be
|
|
* a load of a physical address. We use this either in critical performance
|
|
* path (ivt.S - TLB miss processing) or in places where it might not be
|
|
* safe to use a "tpa" instruction (mca_asm.S - error recovery).
|
|
*/
|
|
.section ".data.patch.vtop", "a" // declare section & section attributes
|
|
.previous
|
|
|
|
#define LOAD_PHYSICAL(pr, reg, obj) \
|
|
[1:](pr)movl reg = obj; \
|
|
.xdata4 ".data.patch.vtop", 1b-.
|
|
|
|
/*
|
|
* For now, we always put in the McKinley E9 workaround. On CPUs that don't need it,
|
|
* we'll patch out the work-around bundles with NOPs, so their impact is minimal.
|
|
*/
|
|
#define DO_MCKINLEY_E9_WORKAROUND
|
|
|
|
#ifdef DO_MCKINLEY_E9_WORKAROUND
|
|
.section ".data.patch.mckinley_e9", "a"
|
|
.previous
|
|
/* workaround for Itanium 2 Errata 9: */
|
|
# define FSYS_RETURN \
|
|
.xdata4 ".data.patch.mckinley_e9", 1f-.; \
|
|
1:{ .mib; \
|
|
nop.m 0; \
|
|
mov r16=ar.pfs; \
|
|
br.call.sptk.many b7=2f;; \
|
|
}; \
|
|
2:{ .mib; \
|
|
nop.m 0; \
|
|
mov ar.pfs=r16; \
|
|
br.ret.sptk.many b6;; \
|
|
}
|
|
#else
|
|
# define FSYS_RETURN br.ret.sptk.many b6
|
|
#endif
|
|
|
|
/*
|
|
* Up until early 2004, use of .align within a function caused bad unwind info.
|
|
* TEXT_ALIGN(n) expands into ".align n" if a fixed GAS is available or into nothing
|
|
* otherwise.
|
|
*/
|
|
#ifdef HAVE_WORKING_TEXT_ALIGN
|
|
# define TEXT_ALIGN(n) .align n
|
|
#else
|
|
# define TEXT_ALIGN(n)
|
|
#endif
|
|
|
|
#ifdef HAVE_SERIALIZE_DIRECTIVE
|
|
# define dv_serialize_data .serialize.data
|
|
# define dv_serialize_instruction .serialize.instruction
|
|
#else
|
|
# define dv_serialize_data
|
|
# define dv_serialize_instruction
|
|
#endif
|
|
|
|
#endif /* _ASM_IA64_ASMMACRO_H */
|