diff options
| -rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index fca97bd3d8ae..f356d3ea0c70 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
| @@ -50,52 +50,72 @@ const char *stack_type_name(enum stack_type type) | |||
| 50 | return NULL; | 50 | return NULL; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | struct estack_layout { | 53 | /** |
| 54 | unsigned int begin; | 54 | * struct estack_pages - Page descriptor for exception stacks |
| 55 | unsigned int end; | 55 | * @offs: Offset from the start of the exception stack area |
| 56 | * @size: Size of the exception stack | ||
| 57 | * @type: Type to store in the stack_info struct | ||
| 58 | */ | ||
| 59 | struct estack_pages { | ||
| 60 | u32 offs; | ||
| 61 | u16 size; | ||
| 62 | u16 type; | ||
| 56 | }; | 63 | }; |
| 57 | 64 | ||
| 58 | #define ESTACK_ENTRY(x) { \ | 65 | #define EPAGERANGE(st) \ |
| 59 | .begin = offsetof(struct cea_exception_stacks, x## _stack), \ | 66 | [PFN_DOWN(CEA_ESTACK_OFFS(st)) ... \ |
| 60 | .end = offsetof(struct cea_exception_stacks, x## _stack_guard) \ | 67 | PFN_DOWN(CEA_ESTACK_OFFS(st) + CEA_ESTACK_SIZE(st) - 1)] = { \ |
| 61 | } | 68 | .offs = CEA_ESTACK_OFFS(st), \ |
| 69 | .size = CEA_ESTACK_SIZE(st), \ | ||
| 70 | .type = STACK_TYPE_EXCEPTION + ESTACK_ ##st, } | ||
| 62 | 71 | ||
| 63 | static const struct estack_layout layout[] = { | 72 | /* |
| 64 | [ ESTACK_DF ] = ESTACK_ENTRY(DF), | 73 | * Array of exception stack page descriptors. If the stack is larger than |
| 65 | [ ESTACK_NMI ] = ESTACK_ENTRY(NMI), | 74 | * PAGE_SIZE, all pages covering a particular stack will have the same |
| 66 | [ ESTACK_DB2 ] = { .begin = 0, .end = 0}, | 75 | * info. The guard pages including the not mapped DB2 stack are zeroed |
| 67 | [ ESTACK_DB1 ] = ESTACK_ENTRY(DB1), | 76 | * out. |
| 68 | [ ESTACK_DB ] = ESTACK_ENTRY(DB), | 77 | */ |
| 69 | [ ESTACK_MCE ] = ESTACK_ENTRY(MCE), | 78 | static const |
| 79 | struct estack_pages estack_pages[CEA_ESTACK_PAGES] ____cacheline_aligned = { | ||
| 80 | EPAGERANGE(DF), | ||
| 81 | EPAGERANGE(NMI), | ||
| 82 | EPAGERANGE(DB1), | ||
| 83 | EPAGERANGE(DB), | ||
| 84 | EPAGERANGE(MCE), | ||
| 70 | }; | 85 | }; |
| 71 | 86 | ||
| 72 | static bool in_exception_stack(unsigned long *stack, struct stack_info *info) | 87 | static bool in_exception_stack(unsigned long *stack, struct stack_info *info) |
| 73 | { | 88 | { |
| 74 | unsigned long estacks, begin, end, stk = (unsigned long)stack; | 89 | unsigned long begin, end, stk = (unsigned long)stack; |
| 90 | const struct estack_pages *ep; | ||
| 75 | struct pt_regs *regs; | 91 | struct pt_regs *regs; |
| 76 | unsigned int k; | 92 | unsigned int k; |
| 77 | 93 | ||
| 78 | BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); | 94 | BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); |
| 79 | 95 | ||
| 80 | estacks = (unsigned long)__this_cpu_read(cea_exception_stacks); | 96 | begin = (unsigned long)__this_cpu_read(cea_exception_stacks); |
| 81 | 97 | end = begin + sizeof(struct cea_exception_stacks); | |
| 82 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | 98 | /* Bail if @stack is outside the exception stack area. */ |
| 83 | begin = estacks + layout[k].begin; | 99 | if (stk < begin || stk >= end) |
| 84 | end = estacks + layout[k].end; | 100 | return false; |
| 85 | regs = (struct pt_regs *)end - 1; | ||
| 86 | 101 | ||
| 87 | if (stk < begin || stk >= end) | 102 | /* Calc page offset from start of exception stacks */ |
| 88 | continue; | 103 | k = (stk - begin) >> PAGE_SHIFT; |
| 104 | /* Lookup the page descriptor */ | ||
| 105 | ep = &estack_pages[k]; | ||
| 106 | /* Guard page? */ | ||
| 107 | if (!ep->size) | ||
| 108 | return false; | ||
| 89 | 109 | ||
| 90 | info->type = STACK_TYPE_EXCEPTION + k; | 110 | begin += (unsigned long)ep->offs; |
| 91 | info->begin = (unsigned long *)begin; | 111 | end = begin + (unsigned long)ep->size; |
| 92 | info->end = (unsigned long *)end; | 112 | regs = (struct pt_regs *)end - 1; |
| 93 | info->next_sp = (unsigned long *)regs->sp; | ||
| 94 | 113 | ||
| 95 | return true; | 114 | info->type = ep->type; |
| 96 | } | 115 | info->begin = (unsigned long *)begin; |
| 97 | 116 | info->end = (unsigned long *)end; | |
| 98 | return false; | 117 | info->next_sp = (unsigned long *)regs->sp; |
| 118 | return true; | ||
| 99 | } | 119 | } |
| 100 | 120 | ||
| 101 | static bool in_irq_stack(unsigned long *stack, struct stack_info *info) | 121 | static bool in_irq_stack(unsigned long *stack, struct stack_info *info) |
