aboutsummaryrefslogtreecommitdiff
path: root/src/atags/atags.c
blob: 3f3d1ba823c95864c90cc862e060c7a503bb3ffc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "atags.h"
#include "utils/io.h"

static inline struct atag_header *next_tag(struct atag_header *tag)
{
  return (struct atag_header*) (((uint32_t*) tag) + tag->size);
}

#define TAG_CONTENTS_FUN(tagname)                               \
  static inline struct atag_##tagname *tagname##_tag_contents   \
  (struct atag_header *tag)                                     \
  {                                                             \
    return (struct atag_##tagname*) (tag + 1);                  \
  }

TAG_CONTENTS_FUN(header)
TAG_CONTENTS_FUN(core)
TAG_CONTENTS_FUN(mem)
TAG_CONTENTS_FUN(videotext)
TAG_CONTENTS_FUN(ramdisk)
TAG_CONTENTS_FUN(initrd2)
TAG_CONTENTS_FUN(serialnr)
TAG_CONTENTS_FUN(revision)
TAG_CONTENTS_FUN(videolfb)
TAG_CONTENTS_FUN(cmdline)

uint32_t find_memory_size(struct atag_header *atags)
{
  // we silently assume there will only be one mem atag
  while (atags->tag != ATAG_MEM && atags->tag != ATAG_NONE)
    atags = next_tag(atags);

  if (atags->tag == ATAG_NONE)
    return 0;

  struct atag_mem *mem_tag = mem_tag_contents(atags);

  // our design assumes address 0x0 is available, so we reject mem
  // atag saying otherwise
  if (mem_tag->start != 0)
    {
      puts("ignoring information about memory, "
	   "that doesn't start at 0x0");
      return 0;
    }

  return mem_tag->size;
}

void print_tag(struct atag_header *tag)
{
#define TAG_CASE(tagname_upcase, tagname_locase, instructions)  \
  case ATAG_##tagname_upcase:                                   \
    puts("ATAG_" #tagname_upcase ":");                          \
      {                                                         \
        struct atag_##tagname_locase *contents =                \
          tagname_locase##_tag_contents(tag);			\
        instructions;                                           \
      }                                                         \
    break
  
  switch (tag->tag)
    {
      TAG_CASE(CORE, core,
               prints("  flags: 0x");
               printhex(contents->flags); puts("");
               prints("  page size: ");
               printdec(contents->pagesize); puts("");
               prints("  root device: ");
               printdec(contents->rootdev); puts(""););
      TAG_CASE(MEM, mem, 
               prints("  memory size: 0x");
               printhex(contents->size); puts("");
               prints("  memory start: 0x");
               printhex(contents->start); puts(""););
      // the rest are unimportant for now,
      // as they're not passed by qemu
      TAG_CASE(VIDEOTEXT, videotext, (void) contents;);
      TAG_CASE(RAMDISK, ramdisk, (void) contents;);
      TAG_CASE(INITRD2, initrd2, (void) contents;);
      TAG_CASE(SERIAL, serialnr, (void) contents;);
      TAG_CASE(REVISION, revision, (void) contents;);
      TAG_CASE(VIDEOLFB, videolfb, (void) contents;);
      TAG_CASE(CMDLINE, cmdline, (void) contents;);

    case ATAG_NONE:
      puts("ATAG_NONE");
      break;
    default:
      prints("!! unknown tag: 0x"); printhex(tag->tag); puts(" !!");
    }
}

void print_atags(struct atag_header *atags)
{
  while (atags->tag != ATAG_NONE)
    {
      print_tag(atags);
      atags = next_tag(atags);
    }

  print_tag(atags); // also print ATAG_NONE
}