linux/arch/arm/kernel/atags_parse.c
<<
>>
Prefs
   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
  33static 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
  39static 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
  53static 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
  65static 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)
  73static 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
  91static 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
 104static 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
 113static 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
 121static 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 */
 143static 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 */
 161static 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
 169static 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
 176const struct machine_desc * __init
 177setup_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