Blame view
kernel/kexec.c
6.76 KB
dc009d924
|
1 |
/* |
2965faa5e
|
2 |
* kexec.c - kexec_load system call |
dc009d924
|
3 4 5 6 7 |
* Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com> * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ |
de90a6bca
|
8 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
c59ede7b7
|
9 |
#include <linux/capability.h> |
dc009d924
|
10 11 |
#include <linux/mm.h> #include <linux/file.h> |
dc009d924
|
12 |
#include <linux/kexec.h> |
8c5a1cf0a
|
13 |
#include <linux/mutex.h> |
dc009d924
|
14 |
#include <linux/list.h> |
dc009d924
|
15 |
#include <linux/syscalls.h> |
a43cac0d9
|
16 |
#include <linux/vmalloc.h> |
2965faa5e
|
17 |
#include <linux/slab.h> |
dc009d924
|
18 |
|
a43cac0d9
|
19 |
#include "kexec_internal.h" |
dabe78628
|
20 21 22 |
static int copy_user_segment_list(struct kimage *image, unsigned long nr_segments, struct kexec_segment __user *segments) |
dc009d924
|
23 |
{ |
dabe78628
|
24 |
int ret; |
dc009d924
|
25 |
size_t segment_bytes; |
dc009d924
|
26 27 28 29 |
/* Read in the segments */ image->nr_segments = nr_segments; segment_bytes = nr_segments * sizeof(*segments); |
dabe78628
|
30 31 32 33 34 35 |
ret = copy_from_user(image->segment, segments, segment_bytes); if (ret) ret = -EFAULT; return ret; } |
255aedd90
|
36 37 38 39 |
static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags) |
dc009d924
|
40 |
{ |
255aedd90
|
41 |
int ret; |
dc009d924
|
42 |
struct kimage *image; |
255aedd90
|
43 44 45 46 47 48 49 |
bool kexec_on_panic = flags & KEXEC_ON_CRASH; if (kexec_on_panic) { /* Verify we have a valid entry point */ if ((entry < crashk_res.start) || (entry > crashk_res.end)) return -EADDRNOTAVAIL; } |
dc009d924
|
50 51 |
/* Allocate and initialize a controlling structure */ |
dabe78628
|
52 53 54 55 56 |
image = do_kimage_alloc_init(); if (!image) return -ENOMEM; image->start = entry; |
255aedd90
|
57 58 |
ret = copy_user_segment_list(image, nr_segments, segments); if (ret) |
dabe78628
|
59 |
goto out_free_image; |
255aedd90
|
60 |
if (kexec_on_panic) { |
cdf4b3fa0
|
61 |
/* Enable special crash kernel control page alloc policy. */ |
255aedd90
|
62 63 64 |
image->control_page = crashk_res.start; image->type = KEXEC_TYPE_CRASH; } |
cdf4b3fa0
|
65 66 67 |
ret = sanity_check_segment_list(image); if (ret) goto out_free_image; |
dc009d924
|
68 69 70 71 72 |
/* * Find a location for the control code buffer, and add it * the vector of segments so that it's pages will also be * counted as destination pages. */ |
255aedd90
|
73 |
ret = -ENOMEM; |
dc009d924
|
74 |
image->control_code_page = kimage_alloc_control_pages(image, |
163f6876f
|
75 |
get_order(KEXEC_CONTROL_PAGE_SIZE)); |
dc009d924
|
76 |
if (!image->control_code_page) { |
e1bebcf41
|
77 78 |
pr_err("Could not allocate control_code_buffer "); |
dabe78628
|
79 |
goto out_free_image; |
dc009d924
|
80 |
} |
255aedd90
|
81 82 83 84 85 86 87 |
if (!kexec_on_panic) { image->swap_page = kimage_alloc_control_pages(image, 0); if (!image->swap_page) { pr_err("Could not allocate swap buffer "); goto out_free_control_pages; } |
3ab835213
|
88 |
} |
b92e7e0da
|
89 90 |
*rimage = image; return 0; |
dabe78628
|
91 |
out_free_control_pages: |
b92e7e0da
|
92 |
kimage_free_page_list(&image->control_pages); |
dabe78628
|
93 |
out_free_image: |
b92e7e0da
|
94 |
kfree(image); |
255aedd90
|
95 |
return ret; |
dc009d924
|
96 |
} |
0eea08678
|
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
static int do_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags) { struct kimage **dest_image, *image; unsigned long i; int ret; if (flags & KEXEC_ON_CRASH) { dest_image = &kexec_crash_image; if (kexec_crash_image) arch_kexec_unprotect_crashkres(); } else { dest_image = &kexec_image; } if (nr_segments == 0) { /* Uninstall image */ kimage_free(xchg(dest_image, NULL)); return 0; } if (flags & KEXEC_ON_CRASH) { /* * Loading another kernel to switch to if this one * crashes. Free any current crash dump kernel before * we corrupt it. */ kimage_free(xchg(&kexec_crash_image, NULL)); } ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags); if (ret) return ret; |
0eea08678
|
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
if (flags & KEXEC_PRESERVE_CONTEXT) image->preserve_context = 1; ret = machine_kexec_prepare(image); if (ret) goto out; for (i = 0; i < nr_segments; i++) { ret = kimage_load_segment(image, &image->segment[i]); if (ret) goto out; } kimage_terminate(image); /* Install the new kernel and uninstall the old */ image = xchg(dest_image, image); out: if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) arch_kexec_protect_crashkres(); |
0eea08678
|
150 151 152 |
kimage_free(image); return ret; } |
dc009d924
|
153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
/* * Exec Kernel system call: for obvious reasons only root may call it. * * This call breaks up into three pieces. * - A generic part which loads the new kernel from the current * address space, and very carefully places the data in the * allocated pages. * * - A generic part that interacts with the kernel and tells all of * the devices to shut down. Preventing on-going dmas, and placing * the devices in a consistent state so a later kernel can * reinitialize them. * * - A machine specific part that includes the syscall number |
002ace782
|
167 |
* and then copies the image to it's final destination. And |
dc009d924
|
168 169 170 171 172 |
* jumps into the image at entry. * * kexec does not sync, or unmount filesystems so if you need * that to happen you need to do that yourself. */ |
8c5a1cf0a
|
173 |
|
754fe8d29
|
174 175 |
SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, struct kexec_segment __user *, segments, unsigned long, flags) |
dc009d924
|
176 |
{ |
dc009d924
|
177 178 179 |
int result; /* We only trust the superuser with rebooting the system. */ |
7984754b9
|
180 |
if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) |
dc009d924
|
181 182 183 184 185 186 187 188 189 190 191 192 |
return -EPERM; /* * Verify we have a legal set of flags * This leaves us room for future extensions. */ if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK)) return -EINVAL; /* Verify we are on the appropriate architecture */ if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) && ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT)) |
dc009d924
|
193 |
return -EINVAL; |
dc009d924
|
194 195 196 197 198 199 |
/* Put an artificial cap on the number * of segments passed to kexec_load. */ if (nr_segments > KEXEC_SEGMENT_MAX) return -EINVAL; |
dc009d924
|
200 201 202 203 204 205 206 207 |
/* Because we write directly to the reserved memory * region when loading crash kernels we need a mutex here to * prevent multiple crash kernels from attempting to load * simultaneously, and to prevent a crash kernel from loading * over the top of a in use crash kernel. * * KISS: always take the mutex. */ |
8c5a1cf0a
|
208 |
if (!mutex_trylock(&kexec_mutex)) |
dc009d924
|
209 |
return -EBUSY; |
72414d3f1
|
210 |
|
0eea08678
|
211 |
result = do_kexec_load(entry, nr_segments, segments, flags); |
dc009d924
|
212 |
|
8c5a1cf0a
|
213 |
mutex_unlock(&kexec_mutex); |
72414d3f1
|
214 |
|
dc009d924
|
215 216 217 218 |
return result; } #ifdef CONFIG_COMPAT |
ca2c405ab
|
219 220 221 222 |
COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry, compat_ulong_t, nr_segments, struct compat_kexec_segment __user *, segments, compat_ulong_t, flags) |
dc009d924
|
223 224 225 226 227 228 229 230 |
{ struct compat_kexec_segment in; struct kexec_segment out, __user *ksegments; unsigned long i, result; /* Don't allow clients that don't understand the native * architecture to do anything. */ |
72414d3f1
|
231 |
if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT) |
dc009d924
|
232 |
return -EINVAL; |
dc009d924
|
233 |
|
72414d3f1
|
234 |
if (nr_segments > KEXEC_SEGMENT_MAX) |
dc009d924
|
235 |
return -EINVAL; |
dc009d924
|
236 237 |
ksegments = compat_alloc_user_space(nr_segments * sizeof(out)); |
e1bebcf41
|
238 |
for (i = 0; i < nr_segments; i++) { |
dc009d924
|
239 |
result = copy_from_user(&in, &segments[i], sizeof(in)); |
72414d3f1
|
240 |
if (result) |
dc009d924
|
241 |
return -EFAULT; |
dc009d924
|
242 243 244 245 246 247 248 |
out.buf = compat_ptr(in.buf); out.bufsz = in.bufsz; out.mem = in.mem; out.memsz = in.memsz; result = copy_to_user(&ksegments[i], &out, sizeof(out)); |
72414d3f1
|
249 |
if (result) |
dc009d924
|
250 |
return -EFAULT; |
dc009d924
|
251 252 253 254 255 |
} return sys_kexec_load(entry, nr_segments, ksegments, flags); } #endif |