1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Based on arch/arm/kernel/atags_proc.c |
4 | */ |
5 | |
6 | #include <linux/fs.h> |
7 | #include <linux/init.h> |
8 | #include <linux/printk.h> |
9 | #include <linux/proc_fs.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/string.h> |
12 | |
13 | #include <asm/bootinfo.h> |
14 | #include <asm/byteorder.h> |
15 | |
16 | |
17 | static char bootinfo_tmp[1536] __initdata; |
18 | |
19 | static void *bootinfo_copy; |
20 | static size_t bootinfo_size; |
21 | |
22 | static ssize_t bootinfo_read(struct file *file, char __user *buf, |
23 | size_t count, loff_t *ppos) |
24 | { |
25 | return simple_read_from_buffer(to: buf, count, ppos, from: bootinfo_copy, |
26 | available: bootinfo_size); |
27 | } |
28 | |
29 | static const struct proc_ops bootinfo_proc_ops = { |
30 | .proc_read = bootinfo_read, |
31 | .proc_lseek = default_llseek, |
32 | }; |
33 | |
34 | void __init save_bootinfo(const struct bi_record *bi) |
35 | { |
36 | const void *start = bi; |
37 | size_t size = sizeof(bi->tag); |
38 | |
39 | while (be16_to_cpu(bi->tag) != BI_LAST) { |
40 | uint16_t n = be16_to_cpu(bi->size); |
41 | size += n; |
42 | bi = (struct bi_record *)((unsigned long)bi + n); |
43 | } |
44 | |
45 | if (size > sizeof(bootinfo_tmp)) { |
46 | pr_err("Cannot save %zu bytes of bootinfo\n" , size); |
47 | return; |
48 | } |
49 | |
50 | pr_info("Saving %zu bytes of bootinfo\n" , size); |
51 | memcpy(bootinfo_tmp, start, size); |
52 | bootinfo_size = size; |
53 | } |
54 | |
55 | static int __init init_bootinfo_procfs(void) |
56 | { |
57 | /* |
58 | * This cannot go into save_bootinfo() because kmalloc and proc don't |
59 | * work yet when it is called. |
60 | */ |
61 | struct proc_dir_entry *pde; |
62 | |
63 | if (!bootinfo_size) |
64 | return -EINVAL; |
65 | |
66 | bootinfo_copy = kmemdup(p: bootinfo_tmp, size: bootinfo_size, GFP_KERNEL); |
67 | if (!bootinfo_copy) |
68 | return -ENOMEM; |
69 | |
70 | pde = proc_create_data("bootinfo" , 0400, NULL, &bootinfo_proc_ops, NULL); |
71 | if (!pde) { |
72 | kfree(objp: bootinfo_copy); |
73 | return -ENOMEM; |
74 | } |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | arch_initcall(init_bootinfo_procfs); |
80 | |