aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kexec.c46
1 files changed, 37 insertions, 9 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 0926f2a3ed03..f18c780f9716 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -548,6 +548,7 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
548{ 548{
549 int ret; 549 int ret;
550 struct kimage *image; 550 struct kimage *image;
551 bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH;
551 552
552 image = do_kimage_alloc_init(); 553 image = do_kimage_alloc_init();
553 if (!image) 554 if (!image)
@@ -555,6 +556,12 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
555 556
556 image->file_mode = 1; 557 image->file_mode = 1;
557 558
559 if (kexec_on_panic) {
560 /* Enable special crash kernel control page alloc policy. */
561 image->control_page = crashk_res.start;
562 image->type = KEXEC_TYPE_CRASH;
563 }
564
558 ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd, 565 ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,
559 cmdline_ptr, cmdline_len, flags); 566 cmdline_ptr, cmdline_len, flags);
560 if (ret) 567 if (ret)
@@ -572,10 +579,12 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
572 goto out_free_post_load_bufs; 579 goto out_free_post_load_bufs;
573 } 580 }
574 581
575 image->swap_page = kimage_alloc_control_pages(image, 0); 582 if (!kexec_on_panic) {
576 if (!image->swap_page) { 583 image->swap_page = kimage_alloc_control_pages(image, 0);
577 pr_err(KERN_ERR "Could not allocate swap buffer\n"); 584 if (!image->swap_page) {
578 goto out_free_control_pages; 585 pr_err(KERN_ERR "Could not allocate swap buffer\n");
586 goto out_free_control_pages;
587 }
579 } 588 }
580 589
581 *rimage = image; 590 *rimage = image;
@@ -1113,10 +1122,14 @@ static int kimage_load_crash_segment(struct kimage *image,
1113 unsigned long maddr; 1122 unsigned long maddr;
1114 size_t ubytes, mbytes; 1123 size_t ubytes, mbytes;
1115 int result; 1124 int result;
1116 unsigned char __user *buf; 1125 unsigned char __user *buf = NULL;
1126 unsigned char *kbuf = NULL;
1117 1127
1118 result = 0; 1128 result = 0;
1119 buf = segment->buf; 1129 if (image->file_mode)
1130 kbuf = segment->kbuf;
1131 else
1132 buf = segment->buf;
1120 ubytes = segment->bufsz; 1133 ubytes = segment->bufsz;
1121 mbytes = segment->memsz; 1134 mbytes = segment->memsz;
1122 maddr = segment->mem; 1135 maddr = segment->mem;
@@ -1139,7 +1152,12 @@ static int kimage_load_crash_segment(struct kimage *image,
1139 /* Zero the trailing part of the page */ 1152 /* Zero the trailing part of the page */
1140 memset(ptr + uchunk, 0, mchunk - uchunk); 1153 memset(ptr + uchunk, 0, mchunk - uchunk);
1141 } 1154 }
1142 result = copy_from_user(ptr, buf, uchunk); 1155
1156 /* For file based kexec, source pages are in kernel memory */
1157 if (image->file_mode)
1158 memcpy(ptr, kbuf, uchunk);
1159 else
1160 result = copy_from_user(ptr, buf, uchunk);
1143 kexec_flush_icache_page(page); 1161 kexec_flush_icache_page(page);
1144 kunmap(page); 1162 kunmap(page);
1145 if (result) { 1163 if (result) {
@@ -1148,7 +1166,10 @@ static int kimage_load_crash_segment(struct kimage *image,
1148 } 1166 }
1149 ubytes -= uchunk; 1167 ubytes -= uchunk;
1150 maddr += mchunk; 1168 maddr += mchunk;
1151 buf += mchunk; 1169 if (image->file_mode)
1170 kbuf += mchunk;
1171 else
1172 buf += mchunk;
1152 mbytes -= mchunk; 1173 mbytes -= mchunk;
1153 } 1174 }
1154out: 1175out:
@@ -2127,7 +2148,14 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
2127 kbuf->top_down = top_down; 2148 kbuf->top_down = top_down;
2128 2149
2129 /* Walk the RAM ranges and allocate a suitable range for the buffer */ 2150 /* Walk the RAM ranges and allocate a suitable range for the buffer */
2130 ret = walk_system_ram_res(0, -1, kbuf, locate_mem_hole_callback); 2151 if (image->type == KEXEC_TYPE_CRASH)
2152 ret = walk_iomem_res("Crash kernel",
2153 IORESOURCE_MEM | IORESOURCE_BUSY,
2154 crashk_res.start, crashk_res.end, kbuf,
2155 locate_mem_hole_callback);
2156 else
2157 ret = walk_system_ram_res(0, -1, kbuf,
2158 locate_mem_hole_callback);
2131 if (ret != 1) { 2159 if (ret != 1) {
2132 /* A suitable memory range could not be found for buffer */ 2160 /* A suitable memory range could not be found for buffer */
2133 return -EADDRNOTAVAIL; 2161 return -EADDRNOTAVAIL;