xref: /linux/arch/arm/kernel/atags_parse.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
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_ARCH_FOOTBRIDGE) && defined(CONFIG_VGA_CONSOLE)
parse_tag_videotext(const struct tag * tag)73  static int __init parse_tag_videotext(const struct tag *tag)
74  {
75  	vgacon_screen_info.orig_x            = tag->u.videotext.x;
76  	vgacon_screen_info.orig_y            = tag->u.videotext.y;
77  	vgacon_screen_info.orig_video_page   = tag->u.videotext.video_page;
78  	vgacon_screen_info.orig_video_mode   = tag->u.videotext.video_mode;
79  	vgacon_screen_info.orig_video_cols   = tag->u.videotext.video_cols;
80  	vgacon_screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
81  	vgacon_screen_info.orig_video_lines  = tag->u.videotext.video_lines;
82  	vgacon_screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
83  	vgacon_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  	strscpy(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  	strscpy(boot_command_line, from, COMMAND_LINE_SIZE);
228  
229  	return mdesc;
230  }
231