I'm working on a kernel for a RaspberryPi 1B+ and I'm having some trouble with the ATAGS. My orientation for the implementation was this page.
The implementation for parsing looks something like this:
typedef struct atag_header
{
uint32_t size;
uint32_t tag_type;
} atag_header;
typedef struct atag_core
{
uint32_t flags;
uint32_t pagesize;
uint32_t rootdevice;
} atag_core;
typedef struct atag_mem
{
uint32_t size;
uint32_t address;
} atag_mem;
/* etc... */
typedef struct atag_t {
atag_header header;
union {
atag_core core;
atag_mem mem;
atag_ramdisk ramdisk;
atag_initrd2 initrd2;
atag_serial serial;
atag_revision revision;
atag_videolfb videolfb;
atag_cmdline cmdline;
};
} atag_t;
#define tag_next(t) ((atag_t *)((uint32_t *)(t) + (t)->header.size))
#define tag_size(type) ((sizeof(atag_header) + sizeof(type)) >> 2)
Now as far as I understand the atag's are passed to the kernel over r2
, i.e.
void kernel(uint32_t r0, uint32_t r1, uint32_t r2)
Now r2
is supposed to be the address at which the list of ATAG's starts. I would like to get the RAM size, so I wrote a little function
uint32_t get_mem_size(atag_t * atags) {
while (atags->header.tag_type != ATAG_NONE) {
if (atags->header.tag_type == ATAG_MEM) {
return atags->mem.size;
}
atags = tag_next(atags);
}
return 0;
}
but this just returns zero (calling it with get_mem_size((atag_t *)r2)
). So, I assumed that I was doing something wrong... Turns out, r2
is always 0x6E750000
and well this is no atag
so of course tag_next
will never reach the memory segment..
I don't really understand what I'm doing wrong. Did I misunderstand something about these atags?
After some trying out I got it to work, but I still don't fully understand what the original problem was.
The way how I got my custom kernel onto the Pi worked something like this:
kernel.img
with custom kernel.Now most of the files on the SD card are actually not necessary when you are writing your custom kernel, in fact, you only need bootcode.bin, start.elf, fixup.dat
and your kernel image. Once I had removed everything the ATAG address switched from 0x6E750000
to 0
. After some digging I found this github repo with the following at the beginning of the kernel_main
// Hack for newer firmware - assume if atags not specified then they are at 0x100
// We also check the zero address in case this is true - see later
if(atags == 0x0)
atags = 0x100;
After adding this to my kernel_main
, the code started working. So it seems my atags are not specified... Not sure why this happens or where exactly I would need to set this up, but this does the trick for now. If anyone knows what is going on here, please feel free to add to this/make your own answer.