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 
parse_tag_core(const struct tag * tag)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 
parse_tag_mem32(const struct tag * tag)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)
parse_tag_videotext(const struct tag * tag)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
parse_tag_ramdisk(const struct tag * tag)91 static int __init parse_tag_ramdisk(const struct tag *tag)
92 {
93 	rd_image_start = tag->u.ramdisk.start;
94 
95 	if (tag->u.ramdisk.size)
96 		rd_size = tag->u.ramdisk.size;
97 
98 	return 0;
99 }
100 
101 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
102 #endif
103 
parse_tag_serialnr(const struct tag * tag)104 static int __init parse_tag_serialnr(const struct tag *tag)
105 {
106 	system_serial_low = tag->u.serialnr.low;
107 	system_serial_high = tag->u.serialnr.high;
108 	return 0;
109 }
110 
111 __tagtable(ATAG_SERIAL, parse_tag_serialnr);
112 
parse_tag_revision(const struct tag * tag)113 static int __init parse_tag_revision(const struct tag *tag)
114 {
115 	system_rev = tag->u.revision.rev;
116 	return 0;
117 }
118 
119 __tagtable(ATAG_REVISION, parse_tag_revision);
120 
parse_tag_cmdline(const struct tag * tag)121 static int __init parse_tag_cmdline(const struct tag *tag)
122 {
123 #if defined(CONFIG_CMDLINE_EXTEND)
124 	strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
125 	strlcat(default_command_line, tag->u.cmdline.cmdline,
126 		COMMAND_LINE_SIZE);
127 #elif defined(CONFIG_CMDLINE_FORCE)
128 	pr_warn("Ignoring tag cmdline (using the default kernel command line)\n");
129 #else
130 	strlcpy(default_command_line, tag->u.cmdline.cmdline,
131 		COMMAND_LINE_SIZE);
132 #endif
133 	return 0;
134 }
135 
136 __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
137 
138 /*
139  * Scan the tag table for this tag, and call its parse function.
140  * The tag table is built by the linker from all the __tagtable
141  * declarations.
142  */
parse_tag(const struct tag * tag)143 static int __init parse_tag(const struct tag *tag)
144 {
145 	extern struct tagtable __tagtable_begin, __tagtable_end;
146 	struct tagtable *t;
147 
148 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
149 		if (tag->hdr.tag == t->tag) {
150 			t->parse(tag);
151 			break;
152 		}
153 
154 	return t < &__tagtable_end;
155 }
156 
157 /*
158  * Parse all tags in the list, checking both the global and architecture
159  * specific tag tables.
160  */
parse_tags(const struct tag * t)161 static void __init parse_tags(const struct tag *t)
162 {
163 	for (; t->hdr.size; t = tag_next(t))
164 		if (!parse_tag(t))
165 			pr_warn("Ignoring unrecognised tag 0x%08x\n",
166 				t->hdr.tag);
167 }
168 
squash_mem_tags(struct tag * tag)169 static void __init squash_mem_tags(struct tag *tag)
170 {
171 	for (; tag->hdr.size; tag = tag_next(tag))
172 		if (tag->hdr.tag == ATAG_MEM)
173 			tag->hdr.tag = ATAG_NONE;
174 }
175 
176 const struct machine_desc * __init
setup_machine_tags(void * atags_vaddr,unsigned int machine_nr)177 setup_machine_tags(void *atags_vaddr, unsigned int machine_nr)
178 {
179 	struct tag *tags = (struct tag *)&default_tags;
180 	const struct machine_desc *mdesc = NULL, *p;
181 	char *from = default_command_line;
182 
183 	default_tags.mem.start = PHYS_OFFSET;
184 
185 	/*
186 	 * locate machine in the list of supported machines.
187 	 */
188 	for_each_machine_desc(p)
189 		if (machine_nr == p->nr) {
190 			pr_info("Machine: %s\n", p->name);
191 			mdesc = p;
192 			break;
193 		}
194 
195 	if (!mdesc)
196 		return NULL;
197 
198 	if (atags_vaddr)
199 		tags = atags_vaddr;
200 	else if (mdesc->atag_offset)
201 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
202 
203 #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
204 	/*
205 	 * If we have the old style parameters, convert them to
206 	 * a tag list.
207 	 */
208 	if (tags->hdr.tag != ATAG_CORE)
209 		convert_to_tag_list(tags);
210 #endif
211 	if (tags->hdr.tag != ATAG_CORE) {
212 		early_print("Warning: Neither atags nor dtb found\n");
213 		tags = (struct tag *)&default_tags;
214 	}
215 
216 	if (mdesc->fixup)
217 		mdesc->fixup(tags, &from);
218 
219 	if (tags->hdr.tag == ATAG_CORE) {
220 		if (memblock_phys_mem_size())
221 			squash_mem_tags(tags);
222 		save_atags(tags);
223 		parse_tags(tags);
224 	}
225 
226 	/* parse_early_param needs a boot_command_line */
227 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
228 
229 	return mdesc;
230 }
231