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