aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--atags.c99
-rw-r--r--atags.h102
-rw-r--r--setup.c14
4 files changed, 213 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index ecf2b2f..feedd79 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ ELFFLAGS=-nostdlib -lgcc
ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stage1.o loader_stage2.o
-KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o strings.o io.o
+KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o strings.o io.o atags.o
PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o strings.o io.o
diff --git a/atags.c b/atags.c
new file mode 100644
index 0000000..9b88724
--- /dev/null
+++ b/atags.c
@@ -0,0 +1,99 @@
+#include "atags.h"
+#include "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)
+ 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
+}
diff --git a/atags.h b/atags.h
new file mode 100644
index 0000000..4b6879f
--- /dev/null
+++ b/atags.h
@@ -0,0 +1,102 @@
+#ifndef ATAGS_H
+#define ATAGS_H
+
+#include <stdint.h>
+
+#define ATAG_NONE 0x00000000
+#define ATAG_CORE 0x54410001
+#define ATAG_MEM 0x54410002
+#define ATAG_VIDEOTEXT 0x54410003
+#define ATAG_RAMDISK 0x54410004
+#define ATAG_INITRD2 0x54420005
+#define ATAG_SERIAL 0x54410006
+#define ATAG_REVISION 0x54410007
+#define ATAG_VIDEOLFB 0x54410008
+#define ATAG_CMDLINE 0x54410009
+
+struct atag_header
+{
+ uint32_t size;
+ uint32_t tag;
+};
+
+struct atag_core
+{
+ uint32_t flags;
+ uint32_t pagesize;
+ uint32_t rootdev;
+};
+
+struct atag_mem
+{
+ uint32_t size;
+ uint32_t start;
+};
+
+struct atag_videotext
+{
+ uint8_t x;
+ uint8_t y;
+ uint16_t video_page;
+ uint8_t video_mode;
+ uint8_t video_cols;
+ uint16_t video_ega_bx;
+ uint8_t video_lines;
+ uint8_t video_isvga;
+ uint16_t video_points;
+};
+
+struct atag_ramdisk
+{
+ uint32_t flags;
+ uint32_t size;
+ uint32_t start;
+};
+
+struct atag_initrd2
+{
+ uint32_t start;
+ uint32_t size;
+};
+
+struct atag_serialnr
+{
+ uint32_t low;
+ uint32_t high;
+};
+
+struct atag_revision
+{
+ uint32_t rev;
+};
+
+struct atag_videolfb
+{
+ uint16_t lfb_width;
+ uint16_t lfb_height;
+ uint16_t lfb_depth;
+ uint16_t lfb_linelength;
+ uint32_t lfb_base;
+ uint32_t lfb_size;
+ uint8_t red_size;
+ uint8_t red_pos;
+ uint8_t green_size;
+ uint8_t green_pos;
+ uint8_t blue_size;
+ uint8_t blue_pos;
+ uint8_t rsvd_size;
+ uint8_t rsvd_pos;
+};
+
+struct atag_cmdline
+{
+ char cmdline[1];
+};
+
+uint32_t find_memory_size(struct atag_header *atags);
+
+void print_tag(struct atag_header *tag);
+
+void print_atags(struct atag_header *atags);
+
+#endif // ATAGS_H
diff --git a/setup.c b/setup.c
index be71547..f0a9d0a 100644
--- a/setup.c
+++ b/setup.c
@@ -2,9 +2,10 @@
#include "io.h"
#include "demo_functionality.h"
#include "paging.h"
+#include "atags.h"
void setup(uint32_t r0, uint32_t machine_type,
- uint32_t atags)
+ struct atag_header *atags)
{
uart_init();
@@ -17,12 +18,19 @@ void setup(uint32_t r0, uint32_t machine_type,
prints("ARM machine type: 0x"); printhext(machine_type); puts("");
- // value 3 introduced by stage1 code, means no atags was found
+ // value 3 introduced by stage1 code means no atags was found
if (r0 == 3)
puts("No ATAGS was found!");
else
{
- prints("ATAGS copied to 0x"); printhex(atags); puts("");
+ prints("ATAGS copied to 0x");
+ printhex((uint32_t) atags); puts("");
+
+ puts("__ ATAGS contents __");
+
+ print_atags(atags);
+
+ puts("__ end of ATAGS contents __");
}
// prints some info