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