GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / arm / kernel / atags_parse.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Tag parsing.
4  *
5  * Copyright (C) 1995-2001 Russell King
6  */
7
8 /*
9  * This is the traditional way of passing data to the kernel at boot time.  Rather
10  * than passing a fixed inflexible structure to the kernel, we pass a list
11  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
12  * tag for the list to be recognised (to distinguish the tagged list from
13  * a param_struct).  The list is terminated with a zero-length tag (this tag
14  * is not parsed in any way).
15  */
16
17 #include <linux/init.h>
18 #include <linux/initrd.h>
19 #include <linux/kernel.h>
20 #include <linux/fs.h>
21 #include <linux/root_dev.h>
22 #include <linux/screen_info.h>
23 #include <linux/memblock.h>
24 #include <uapi/linux/mount.h>
25
26 #include <asm/setup.h>
27 #include <asm/system_info.h>
28 #include <asm/page.h>
29 #include <asm/mach/arch.h>
30
31 #include "atags.h"
32
33 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
34
35 #ifndef MEM_SIZE
36 #define MEM_SIZE        (16*1024*1024)
37 #endif
38
39 static struct {
40         struct tag_header hdr1;
41         struct tag_core   core;
42         struct tag_header hdr2;
43         struct tag_mem32  mem;
44         struct tag_header hdr3;
45 } default_tags __initdata = {
46         { tag_size(tag_core), ATAG_CORE },
47         { 1, PAGE_SIZE, 0xff },
48         { tag_size(tag_mem32), ATAG_MEM },
49         { MEM_SIZE },
50         { 0, ATAG_NONE }
51 };
52
53 static int __init parse_tag_core(const struct tag *tag)
54 {
55         if (tag->hdr.size > 2) {
56                 if ((tag->u.core.flags & 1) == 0)
57                         root_mountflags &= ~MS_RDONLY;
58                 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
59         }
60         return 0;
61 }
62
63 __tagtable(ATAG_CORE, parse_tag_core);
64
65 static int __init parse_tag_mem32(const struct tag *tag)
66 {
67         return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
68 }
69
70 __tagtable(ATAG_MEM, parse_tag_mem32);
71
72 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
73 static int __init parse_tag_videotext(const struct tag *tag)
74 {
75         screen_info.orig_x            = tag->u.videotext.x;
76         screen_info.orig_y            = tag->u.videotext.y;
77         screen_info.orig_video_page   = tag->u.videotext.video_page;
78         screen_info.orig_video_mode   = tag->u.videotext.video_mode;
79         screen_info.orig_video_cols   = tag->u.videotext.video_cols;
80         screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
81         screen_info.orig_video_lines  = tag->u.videotext.video_lines;
82         screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
83         screen_info.orig_video_points = tag->u.videotext.video_points;
84         return 0;
85 }
86
87 __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
88 #endif
89
90 #ifdef CONFIG_BLK_DEV_RAM
91 static int __init parse_tag_ramdisk(const struct tag *tag)
92 {
93         rd_image_start = tag->u.ramdisk.start;
94         rd_doload = (tag->u.ramdisk.flags & 1) == 0;
95         rd_prompt = (tag->u.ramdisk.flags & 2) == 0;
96
97         if (tag->u.ramdisk.size)
98                 rd_size = tag->u.ramdisk.size;
99
100         return 0;
101 }
102
103 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
104 #endif
105
106 static int __init parse_tag_serialnr(const struct tag *tag)
107 {
108         system_serial_low = tag->u.serialnr.low;
109         system_serial_high = tag->u.serialnr.high;
110         return 0;
111 }
112
113 __tagtable(ATAG_SERIAL, parse_tag_serialnr);
114
115 static int __init parse_tag_revision(const struct tag *tag)
116 {
117         system_rev = tag->u.revision.rev;
118         return 0;
119 }
120
121 __tagtable(ATAG_REVISION, parse_tag_revision);
122
123 static int __init parse_tag_cmdline(const struct tag *tag)
124 {
125 #if defined(CONFIG_CMDLINE_EXTEND)
126         strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
127         strlcat(default_command_line, tag->u.cmdline.cmdline,
128                 COMMAND_LINE_SIZE);
129 #elif defined(CONFIG_CMDLINE_FORCE)
130         pr_warn("Ignoring tag cmdline (using the default kernel command line)\n");
131 #else
132         strlcpy(default_command_line, tag->u.cmdline.cmdline,
133                 COMMAND_LINE_SIZE);
134 #endif
135         return 0;
136 }
137
138 __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
139
140 /*
141  * Scan the tag table for this tag, and call its parse function.
142  * The tag table is built by the linker from all the __tagtable
143  * declarations.
144  */
145 static int __init parse_tag(const struct tag *tag)
146 {
147         extern struct tagtable __tagtable_begin, __tagtable_end;
148         struct tagtable *t;
149
150         for (t = &__tagtable_begin; t < &__tagtable_end; t++)
151                 if (tag->hdr.tag == t->tag) {
152                         t->parse(tag);
153                         break;
154                 }
155
156         return t < &__tagtable_end;
157 }
158
159 /*
160  * Parse all tags in the list, checking both the global and architecture
161  * specific tag tables.
162  */
163 static void __init parse_tags(const struct tag *t)
164 {
165         for (; t->hdr.size; t = tag_next(t))
166                 if (!parse_tag(t))
167                         pr_warn("Ignoring unrecognised tag 0x%08x\n",
168                                 t->hdr.tag);
169 }
170
171 static void __init squash_mem_tags(struct tag *tag)
172 {
173         for (; tag->hdr.size; tag = tag_next(tag))
174                 if (tag->hdr.tag == ATAG_MEM)
175                         tag->hdr.tag = ATAG_NONE;
176 }
177
178 const struct machine_desc * __init
179 setup_machine_tags(void *atags_vaddr, unsigned int machine_nr)
180 {
181         struct tag *tags = (struct tag *)&default_tags;
182         const struct machine_desc *mdesc = NULL, *p;
183         char *from = default_command_line;
184
185         default_tags.mem.start = PHYS_OFFSET;
186
187         /*
188          * locate machine in the list of supported machines.
189          */
190         for_each_machine_desc(p)
191                 if (machine_nr == p->nr) {
192                         pr_info("Machine: %s\n", p->name);
193                         mdesc = p;
194                         break;
195                 }
196
197         if (!mdesc)
198                 return NULL;
199
200         if (atags_vaddr)
201                 tags = atags_vaddr;
202         else if (mdesc->atag_offset)
203                 tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
204
205 #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
206         /*
207          * If we have the old style parameters, convert them to
208          * a tag list.
209          */
210         if (tags->hdr.tag != ATAG_CORE)
211                 convert_to_tag_list(tags);
212 #endif
213         if (tags->hdr.tag != ATAG_CORE) {
214                 early_print("Warning: Neither atags nor dtb found\n");
215                 tags = (struct tag *)&default_tags;
216         }
217
218         if (mdesc->fixup)
219                 mdesc->fixup(tags, &from);
220
221         if (tags->hdr.tag == ATAG_CORE) {
222                 if (memblock_phys_mem_size())
223                         squash_mem_tags(tags);
224                 save_atags(tags);
225                 parse_tags(tags);
226         }
227
228         /* parse_early_param needs a boot_command_line */
229         strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
230
231         return mdesc;
232 }