1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/slab.h> 3 #include <linux/proc_fs.h> 4 #include <asm/setup.h> 5 #include <asm/types.h> 6 #include <asm/page.h> 7 8 struct buffer { 9 size_t size; 10 char data[]; 11 }; 12 13 static ssize_t atags_read(struct file *file, char __user *buf, 14 size_t count, loff_t *ppos) 15 { 16 struct buffer *b = PDE_DATA(file_inode(file)); 17 return simple_read_from_buffer(buf, count, ppos, b->data, b->size); 18 } 19 20 static const struct file_operations atags_fops = { 21 .read = atags_read, 22 .llseek = default_llseek, 23 }; 24 25 #define BOOT_PARAMS_SIZE 1536 26 static char __initdata atags_copy[BOOT_PARAMS_SIZE]; 27 28 void __init save_atags(const struct tag *tags) 29 { 30 memcpy(atags_copy, tags, sizeof(atags_copy)); 31 } 32 33 static int __init init_atags_procfs(void) 34 { 35 /* 36 * This cannot go into save_atags() because kmalloc and proc don't work 37 * yet when it is called. 38 */ 39 struct proc_dir_entry *tags_entry; 40 struct tag *tag = (struct tag *)atags_copy; 41 struct buffer *b; 42 size_t size; 43 44 if (tag->hdr.tag != ATAG_CORE) { 45 pr_info("No ATAGs?"); 46 return -EINVAL; 47 } 48 49 for (; tag->hdr.size; tag = tag_next(tag)) 50 ; 51 52 /* include the terminating ATAG_NONE */ 53 size = (char *)tag - atags_copy + sizeof(struct tag_header); 54 55 WARN_ON(tag->hdr.tag != ATAG_NONE); 56 57 b = kmalloc(sizeof(*b) + size, GFP_KERNEL); 58 if (!b) 59 goto nomem; 60 61 b->size = size; 62 memcpy(b->data, atags_copy, size); 63 64 tags_entry = proc_create_data("atags", 0400, NULL, &atags_fops, b); 65 if (!tags_entry) 66 goto nomem; 67 68 return 0; 69 70 nomem: 71 kfree(b); 72 pr_err("Exporting ATAGs: not enough memory\n"); 73 74 return -ENOMEM; 75 } 76 arch_initcall(init_atags_procfs); 77