linux/arch/arm/kernel/atags_parse.c
<<
>>
Prefs
   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
  34static 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
  40static 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
  54static 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
  66static 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)
  74static 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
  92static 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
 109static 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
 118static 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
 126static 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_warning("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 */
 148static 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 */
 166static void __init parse_tags(const struct tag *t)
 167{
 168        for (; t->hdr.size; t = tag_next(t))
 169                if (!parse_tag(t))
 170                        printk(KERN_WARNING
 171                                "Ignoring unrecognised tag 0x%08x\n",
 172                                t->hdr.tag);
 173}
 174
 175static void __init squash_mem_tags(struct tag *tag)
 176{
 177        for (; tag->hdr.size; tag = tag_next(tag))
 178                if (tag->hdr.tag == ATAG_MEM)
 179                        tag->hdr.tag = ATAG_NONE;
 180}
 181
 182const struct machine_desc * __init
 183setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
 184{
 185        struct tag *tags = (struct tag *)&default_tags;
 186        const struct machine_desc *mdesc = NULL, *p;
 187        char *from = default_command_line;
 188
 189        default_tags.mem.start = PHYS_OFFSET;
 190
 191        /*
 192         * locate machine in the list of supported machines.
 193         */
 194        for_each_machine_desc(p)
 195                if (machine_nr == p->nr) {
 196                        printk("Machine: %s\n", p->name);
 197                        mdesc = p;
 198                        break;
 199                }
 200
 201        if (!mdesc) {
 202                early_print("\nError: unrecognized/unsupported machine ID"
 203                            " (r1 = 0x%08x).\n\n", machine_nr);
 204                dump_machine_table(); /* does not return */
 205        }
 206
 207        if (__atags_pointer)
 208                tags = phys_to_virt(__atags_pointer);
 209        else if (mdesc->atag_offset)
 210                tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
 211
 212#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
 213        /*
 214         * If we have the old style parameters, convert them to
 215         * a tag list.
 216         */
 217        if (tags->hdr.tag != ATAG_CORE)
 218                convert_to_tag_list(tags);
 219#endif
 220        if (tags->hdr.tag != ATAG_CORE) {
 221                early_print("Warning: Neither atags nor dtb found\n");
 222                tags = (struct tag *)&default_tags;
 223        }
 224
 225        if (mdesc->fixup)
 226                mdesc->fixup(tags, &from);
 227
 228        if (tags->hdr.tag == ATAG_CORE) {
 229                if (memblock_phys_mem_size())
 230                        squash_mem_tags(tags);
 231                save_atags(tags);
 232                parse_tags(tags);
 233        }
 234
 235        /* parse_early_param needs a boot_command_line */
 236        strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
 237
 238        return mdesc;
 239}
 240