diff options
author | Philipp Rudo <prudo@linux.vnet.ibm.com> | 2017-08-30 08:03:38 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-04-16 03:10:22 -0400 |
commit | e49bb0a27fa3c6ec45cc13e2102a6ec13c4ae697 (patch) | |
tree | d4365a12b7eb3e8cf8bd811c4075771ec2e20320 | |
parent | 71406883fd35794d573b3085433c41d0a3bf6c21 (diff) |
s390/kexec_file: Add image loader
Add an image loader for kexec_file_load. For simplicity first skip crash
support. The functions defined in machine_kexec_file will later be shared
with the ELF loader.
Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/kexec.h | 22 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/kexec_image.c | 78 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec_file.c | 75 |
4 files changed, 176 insertions, 1 deletions
diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index 1d708a419326..4c9da9974cf4 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h | |||
@@ -46,4 +46,26 @@ | |||
46 | static inline void crash_setup_regs(struct pt_regs *newregs, | 46 | static inline void crash_setup_regs(struct pt_regs *newregs, |
47 | struct pt_regs *oldregs) { } | 47 | struct pt_regs *oldregs) { } |
48 | 48 | ||
49 | struct kimage; | ||
50 | struct s390_load_data { | ||
51 | /* Pointer to the kernel buffer. Used to register cmdline etc.. */ | ||
52 | void *kernel_buf; | ||
53 | |||
54 | /* Total size of loaded segments in memory. Used as an offset. */ | ||
55 | size_t memsz; | ||
56 | |||
57 | /* Load address of initrd. Used to register INITRD_START in kernel. */ | ||
58 | unsigned long initrd_load_addr; | ||
59 | }; | ||
60 | |||
61 | int kexec_file_add_purgatory(struct kimage *image, | ||
62 | struct s390_load_data *data); | ||
63 | int kexec_file_add_initrd(struct kimage *image, | ||
64 | struct s390_load_data *data, | ||
65 | char *initrd, unsigned long initrd_len); | ||
66 | int *kexec_file_update_kernel(struct kimage *iamge, | ||
67 | struct s390_load_data *data); | ||
68 | |||
69 | extern const struct kexec_file_ops s390_kexec_image_ops; | ||
70 | |||
49 | #endif /*_S390_KEXEC_H */ | 71 | #endif /*_S390_KEXEC_H */ |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 35bec1ab84e3..a84e9611c5c7 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -82,7 +82,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o | |||
82 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 82 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
83 | obj-$(CONFIG_UPROBES) += uprobes.o | 83 | obj-$(CONFIG_UPROBES) += uprobes.o |
84 | 84 | ||
85 | obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o | 85 | obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o |
86 | 86 | ||
87 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o | 87 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o |
88 | obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o | 88 | obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o |
diff --git a/arch/s390/kernel/kexec_image.c b/arch/s390/kernel/kexec_image.c new file mode 100644 index 000000000000..7f5021e6c242 --- /dev/null +++ b/arch/s390/kernel/kexec_image.c | |||
@@ -0,0 +1,78 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Image loader for kexec_file_load system call. | ||
4 | * | ||
5 | * Copyright IBM Corp. 2018 | ||
6 | * | ||
7 | * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com> | ||
8 | */ | ||
9 | |||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/kexec.h> | ||
13 | #include <asm/setup.h> | ||
14 | |||
15 | static int kexec_file_add_image_kernel(struct kimage *image, | ||
16 | struct s390_load_data *data, | ||
17 | char *kernel, unsigned long kernel_len) | ||
18 | { | ||
19 | struct kexec_buf buf; | ||
20 | int ret; | ||
21 | |||
22 | buf.image = image; | ||
23 | |||
24 | buf.buffer = kernel + STARTUP_NORMAL_OFFSET; | ||
25 | buf.bufsz = kernel_len - STARTUP_NORMAL_OFFSET; | ||
26 | |||
27 | buf.mem = STARTUP_NORMAL_OFFSET; | ||
28 | buf.memsz = buf.bufsz; | ||
29 | |||
30 | ret = kexec_add_buffer(&buf); | ||
31 | |||
32 | data->kernel_buf = kernel; | ||
33 | data->memsz += buf.memsz + STARTUP_NORMAL_OFFSET; | ||
34 | |||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | static void *s390_image_load(struct kimage *image, | ||
39 | char *kernel, unsigned long kernel_len, | ||
40 | char *initrd, unsigned long initrd_len, | ||
41 | char *cmdline, unsigned long cmdline_len) | ||
42 | { | ||
43 | struct s390_load_data data = {0}; | ||
44 | int ret; | ||
45 | |||
46 | /* We don't support crash kernels yet. */ | ||
47 | if (image->type == KEXEC_TYPE_CRASH) | ||
48 | return ERR_PTR(-ENOTSUPP); | ||
49 | |||
50 | ret = kexec_file_add_image_kernel(image, &data, kernel, kernel_len); | ||
51 | if (ret) | ||
52 | return ERR_PTR(ret); | ||
53 | |||
54 | if (initrd) { | ||
55 | ret = kexec_file_add_initrd(image, &data, initrd, initrd_len); | ||
56 | if (ret) | ||
57 | return ERR_PTR(ret); | ||
58 | } | ||
59 | |||
60 | ret = kexec_file_add_purgatory(image, &data); | ||
61 | if (ret) | ||
62 | return ERR_PTR(ret); | ||
63 | |||
64 | return kexec_file_update_kernel(image, &data); | ||
65 | } | ||
66 | |||
67 | static int s390_image_probe(const char *buf, unsigned long len) | ||
68 | { | ||
69 | /* Can't reliably tell if an image is valid. Therefore give the | ||
70 | * user whatever he wants. | ||
71 | */ | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | const struct kexec_file_ops s390_kexec_image_ops = { | ||
76 | .probe = s390_image_probe, | ||
77 | .load = s390_image_load, | ||
78 | }; | ||
diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index d9b4f9d23e9f..2a2ceece77b0 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c | |||
@@ -12,9 +12,84 @@ | |||
12 | #include <asm/setup.h> | 12 | #include <asm/setup.h> |
13 | 13 | ||
14 | const struct kexec_file_ops * const kexec_file_loaders[] = { | 14 | const struct kexec_file_ops * const kexec_file_loaders[] = { |
15 | &s390_kexec_image_ops, | ||
15 | NULL, | 16 | NULL, |
16 | }; | 17 | }; |
17 | 18 | ||
19 | int *kexec_file_update_kernel(struct kimage *image, | ||
20 | struct s390_load_data *data) | ||
21 | { | ||
22 | unsigned long *loc; | ||
23 | |||
24 | if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) | ||
25 | return ERR_PTR(-EINVAL); | ||
26 | |||
27 | if (image->cmdline_buf_len) | ||
28 | memcpy(data->kernel_buf + COMMAND_LINE_OFFSET, | ||
29 | image->cmdline_buf, image->cmdline_buf_len); | ||
30 | |||
31 | if (image->initrd_buf) { | ||
32 | loc = (unsigned long *)(data->kernel_buf + INITRD_START_OFFSET); | ||
33 | *loc = data->initrd_load_addr; | ||
34 | |||
35 | loc = (unsigned long *)(data->kernel_buf + INITRD_SIZE_OFFSET); | ||
36 | *loc = image->initrd_buf_len; | ||
37 | } | ||
38 | |||
39 | return NULL; | ||
40 | } | ||
41 | |||
42 | static int kexec_file_update_purgatory(struct kimage *image) | ||
43 | { | ||
44 | u64 entry, type; | ||
45 | int ret; | ||
46 | |||
47 | entry = STARTUP_NORMAL_OFFSET; | ||
48 | ret = kexec_purgatory_get_set_symbol(image, "kernel_entry", &entry, | ||
49 | sizeof(entry), false); | ||
50 | return ret; | ||
51 | } | ||
52 | |||
53 | int kexec_file_add_purgatory(struct kimage *image, struct s390_load_data *data) | ||
54 | { | ||
55 | struct kexec_buf buf; | ||
56 | int ret; | ||
57 | |||
58 | buf.image = image; | ||
59 | |||
60 | data->memsz = ALIGN(data->memsz, PAGE_SIZE); | ||
61 | buf.mem = data->memsz; | ||
62 | |||
63 | ret = kexec_load_purgatory(image, &buf); | ||
64 | if (ret) | ||
65 | return ret; | ||
66 | |||
67 | ret = kexec_file_update_purgatory(image); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | int kexec_file_add_initrd(struct kimage *image, struct s390_load_data *data, | ||
72 | char *initrd, unsigned long initrd_len) | ||
73 | { | ||
74 | struct kexec_buf buf; | ||
75 | int ret; | ||
76 | |||
77 | buf.image = image; | ||
78 | |||
79 | buf.buffer = initrd; | ||
80 | buf.bufsz = initrd_len; | ||
81 | |||
82 | data->memsz = ALIGN(data->memsz, PAGE_SIZE); | ||
83 | buf.mem = data->memsz; | ||
84 | buf.memsz = buf.bufsz; | ||
85 | |||
86 | data->initrd_load_addr = buf.mem; | ||
87 | data->memsz += buf.memsz; | ||
88 | |||
89 | ret = kexec_add_buffer(&buf); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
18 | /* | 93 | /* |
19 | * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole | 94 | * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole |
20 | * and provide kbuf->mem by hand. | 95 | * and provide kbuf->mem by hand. |