diff options
author | Geert Uytterhoeven <geert@linux-m68k.org> | 2013-08-21 16:36:32 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2013-12-08 05:01:48 -0500 |
commit | 7bc1e4d8d506462c7d40118196f79a709f3fecfd (patch) | |
tree | e9d72b9a9e1e0368b9d3e3a9ccae929fd2ab947e | |
parent | 7d5f5fa276efbbe45f0ed270b3f4e4a2816398c2 (diff) |
m68k: Add support to export bootinfo in procfs
Add optional support to export the bootinfo used to boot the kernel in a
"bootinfo" file in procfs. This is useful with kexec.
This is based on the similar feature for ATAGS on ARM.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-rw-r--r-- | arch/m68k/Kconfig | 7 | ||||
-rw-r--r-- | arch/m68k/include/asm/bootinfo.h | 12 | ||||
-rw-r--r-- | arch/m68k/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/m68k/kernel/bootinfo_proc.c | 80 | ||||
-rw-r--r-- | arch/m68k/kernel/setup_mm.c | 2 |
5 files changed, 102 insertions, 0 deletions
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 178dffa9de80..dbdd2231c75d 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig | |||
@@ -104,6 +104,13 @@ config KEXEC | |||
104 | interface is strongly in flux, so no good recommendation can be | 104 | interface is strongly in flux, so no good recommendation can be |
105 | made. | 105 | made. |
106 | 106 | ||
107 | config BOOTINFO_PROC | ||
108 | bool "Export bootinfo in procfs" | ||
109 | depends on KEXEC && M68KCLASSIC | ||
110 | help | ||
111 | Say Y to export the bootinfo used to boot the kernel in a | ||
112 | "bootinfo" file in procfs. This is useful with kexec. | ||
113 | |||
107 | menu "Platform setup" | 114 | menu "Platform setup" |
108 | 115 | ||
109 | source arch/m68k/Kconfig.cpu | 116 | source arch/m68k/Kconfig.cpu |
diff --git a/arch/m68k/include/asm/bootinfo.h b/arch/m68k/include/asm/bootinfo.h index 9edc31893fb8..8e213267f8e7 100644 --- a/arch/m68k/include/asm/bootinfo.h +++ b/arch/m68k/include/asm/bootinfo.h | |||
@@ -13,4 +13,16 @@ | |||
13 | 13 | ||
14 | #include <uapi/asm/bootinfo.h> | 14 | #include <uapi/asm/bootinfo.h> |
15 | 15 | ||
16 | |||
17 | #ifndef __ASSEMBLY__ | ||
18 | |||
19 | #ifdef CONFIG_BOOTINFO_PROC | ||
20 | extern void save_bootinfo(const struct bi_record *bi); | ||
21 | #else | ||
22 | static inline void save_bootinfo(const struct bi_record *bi) {} | ||
23 | #endif | ||
24 | |||
25 | #endif /* __ASSEMBLY__ */ | ||
26 | |||
27 | |||
16 | #endif /* _M68K_BOOTINFO_H */ | 28 | #endif /* _M68K_BOOTINFO_H */ |
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 7ee5f00a9abb..2d5d9be16273 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile | |||
@@ -23,4 +23,5 @@ obj-$(CONFIG_PCI) += pcibios.o | |||
23 | obj-$(CONFIG_HAS_DMA) += dma.o | 23 | obj-$(CONFIG_HAS_DMA) += dma.o |
24 | 24 | ||
25 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 25 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
26 | obj-$(CONFIG_BOOTINFO_PROC) += bootinfo_proc.o | ||
26 | 27 | ||
diff --git a/arch/m68k/kernel/bootinfo_proc.c b/arch/m68k/kernel/bootinfo_proc.c new file mode 100644 index 000000000000..7ee853e1432b --- /dev/null +++ b/arch/m68k/kernel/bootinfo_proc.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/kernel/atags_proc.c | ||
3 | */ | ||
4 | |||
5 | #include <linux/fs.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/printk.h> | ||
8 | #include <linux/proc_fs.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/string.h> | ||
11 | |||
12 | #include <asm/bootinfo.h> | ||
13 | #include <asm/byteorder.h> | ||
14 | |||
15 | |||
16 | static char bootinfo_tmp[1536] __initdata; | ||
17 | |||
18 | static void *bootinfo_copy; | ||
19 | static size_t bootinfo_size; | ||
20 | |||
21 | static ssize_t bootinfo_read(struct file *file, char __user *buf, | ||
22 | size_t count, loff_t *ppos) | ||
23 | { | ||
24 | return simple_read_from_buffer(buf, count, ppos, bootinfo_copy, | ||
25 | bootinfo_size); | ||
26 | } | ||
27 | |||
28 | static const struct file_operations bootinfo_fops = { | ||
29 | .read = bootinfo_read, | ||
30 | .llseek = default_llseek, | ||
31 | }; | ||
32 | |||
33 | void __init save_bootinfo(const struct bi_record *bi) | ||
34 | { | ||
35 | const void *start = bi; | ||
36 | size_t size = sizeof(bi->tag); | ||
37 | |||
38 | while (be16_to_cpu(bi->tag) != BI_LAST) { | ||
39 | uint16_t n = be16_to_cpu(bi->size); | ||
40 | size += n; | ||
41 | bi = (struct bi_record *)((unsigned long)bi + n); | ||
42 | } | ||
43 | |||
44 | if (size > sizeof(bootinfo_tmp)) { | ||
45 | pr_err("Cannot save %zu bytes of bootinfo\n", size); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | pr_info("Saving %zu bytes of bootinfo\n", size); | ||
50 | memcpy(bootinfo_tmp, start, size); | ||
51 | bootinfo_size = size; | ||
52 | } | ||
53 | |||
54 | static int __init init_bootinfo_procfs(void) | ||
55 | { | ||
56 | /* | ||
57 | * This cannot go into save_bootinfo() because kmalloc and proc don't | ||
58 | * work yet when it is called. | ||
59 | */ | ||
60 | struct proc_dir_entry *pde; | ||
61 | |||
62 | if (!bootinfo_size) | ||
63 | return -EINVAL; | ||
64 | |||
65 | bootinfo_copy = kmalloc(bootinfo_size, GFP_KERNEL); | ||
66 | if (!bootinfo_copy) | ||
67 | return -ENOMEM; | ||
68 | |||
69 | memcpy(bootinfo_copy, bootinfo_tmp, bootinfo_size); | ||
70 | |||
71 | pde = proc_create_data("bootinfo", 0400, NULL, &bootinfo_fops, NULL); | ||
72 | if (!pde) { | ||
73 | kfree(bootinfo_copy); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | arch_initcall(init_bootinfo_procfs); | ||
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c index 28abca421974..5b8ec4d5f8e8 100644 --- a/arch/m68k/kernel/setup_mm.c +++ b/arch/m68k/kernel/setup_mm.c | |||
@@ -146,6 +146,8 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record) | |||
146 | { | 146 | { |
147 | uint16_t tag; | 147 | uint16_t tag; |
148 | 148 | ||
149 | save_bootinfo(record); | ||
150 | |||
149 | while ((tag = be16_to_cpu(record->tag)) != BI_LAST) { | 151 | while ((tag = be16_to_cpu(record->tag)) != BI_LAST) { |
150 | int unknown = 0; | 152 | int unknown = 0; |
151 | const void *data = record->data; | 153 | const void *data = record->data; |