diff options
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r-- | kernel/kexec.c | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index fcdd5d2bc3f4..afbbbe981be2 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
21 | #include <linux/ioport.h> | 21 | #include <linux/ioport.h> |
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <linux/elf.h> | ||
24 | #include <linux/elfcore.h> | ||
23 | 25 | ||
24 | #include <asm/page.h> | 26 | #include <asm/page.h> |
25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
@@ -108,11 +110,10 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, | |||
108 | 110 | ||
109 | /* Allocate a controlling structure */ | 111 | /* Allocate a controlling structure */ |
110 | result = -ENOMEM; | 112 | result = -ENOMEM; |
111 | image = kmalloc(sizeof(*image), GFP_KERNEL); | 113 | image = kzalloc(sizeof(*image), GFP_KERNEL); |
112 | if (!image) | 114 | if (!image) |
113 | goto out; | 115 | goto out; |
114 | 116 | ||
115 | memset(image, 0, sizeof(*image)); | ||
116 | image->head = 0; | 117 | image->head = 0; |
117 | image->entry = &image->head; | 118 | image->entry = &image->head; |
118 | image->last_entry = &image->head; | 119 | image->last_entry = &image->head; |
@@ -1067,6 +1068,60 @@ void crash_kexec(struct pt_regs *regs) | |||
1067 | } | 1068 | } |
1068 | } | 1069 | } |
1069 | 1070 | ||
1071 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
1072 | size_t data_len) | ||
1073 | { | ||
1074 | struct elf_note note; | ||
1075 | |||
1076 | note.n_namesz = strlen(name) + 1; | ||
1077 | note.n_descsz = data_len; | ||
1078 | note.n_type = type; | ||
1079 | memcpy(buf, ¬e, sizeof(note)); | ||
1080 | buf += (sizeof(note) + 3)/4; | ||
1081 | memcpy(buf, name, note.n_namesz); | ||
1082 | buf += (note.n_namesz + 3)/4; | ||
1083 | memcpy(buf, data, note.n_descsz); | ||
1084 | buf += (note.n_descsz + 3)/4; | ||
1085 | |||
1086 | return buf; | ||
1087 | } | ||
1088 | |||
1089 | static void final_note(u32 *buf) | ||
1090 | { | ||
1091 | struct elf_note note; | ||
1092 | |||
1093 | note.n_namesz = 0; | ||
1094 | note.n_descsz = 0; | ||
1095 | note.n_type = 0; | ||
1096 | memcpy(buf, ¬e, sizeof(note)); | ||
1097 | } | ||
1098 | |||
1099 | void crash_save_cpu(struct pt_regs *regs, int cpu) | ||
1100 | { | ||
1101 | struct elf_prstatus prstatus; | ||
1102 | u32 *buf; | ||
1103 | |||
1104 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
1105 | return; | ||
1106 | |||
1107 | /* Using ELF notes here is opportunistic. | ||
1108 | * I need a well defined structure format | ||
1109 | * for the data I pass, and I need tags | ||
1110 | * on the data to indicate what information I have | ||
1111 | * squirrelled away. ELF notes happen to provide | ||
1112 | * all of that, so there is no need to invent something new. | ||
1113 | */ | ||
1114 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
1115 | if (!buf) | ||
1116 | return; | ||
1117 | memset(&prstatus, 0, sizeof(prstatus)); | ||
1118 | prstatus.pr_pid = current->pid; | ||
1119 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
1120 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
1121 | sizeof(prstatus)); | ||
1122 | final_note(buf); | ||
1123 | } | ||
1124 | |||
1070 | static int __init crash_notes_memory_init(void) | 1125 | static int __init crash_notes_memory_init(void) |
1071 | { | 1126 | { |
1072 | /* Allocate memory for saving cpu registers. */ | 1127 | /* Allocate memory for saving cpu registers. */ |