some platforms are getting a -t option to exec which will setup the tags for the kernel. Also the following code might be helpful to create your own app that sets them up before you do "exec":
/***************************************************************************
* Copyright (C) 2007 by Hasan Hüseyin Y?lmaz *
* hasanhuseyin.yilmaz@vestel.com.tr *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "bootloaderstg2.h"
static void setup_core_tag(u32 address,long pagesize);
static void setup_ramdisk_tag(u32 size);
static void setup_initrd2_tag(u32 start, u32 size);
static void setup_mem_tag(u32 start, u32 len);
static void setup_cmdline_tag(const char *line);
static void setup_end_tag(void);
static void setup_tags();
static int puts(const char *src);
#define SDRAM_BASE 0x80000000
#define SDRAM_SIZE 0x4000000
#define LINUX_LOAD_BASE 0x81000000
#define PARAM_LOAD_ADDRESS_BASE 0x80000100
#define MACHINE_TYPE 1236
#if 0
// #define INITRD_LOAD_ADDRESS (LINUX_LOAD_BASE + 0x800000)
/* see arch/arm/tools/mach-types */
#define PARAM_BASE \
"ldr r0, =0x0\n\
ldr r1, =0x4d5\n\
ldr r2, =0xa0000100"
#endif
int
main(int argc,char *argv[])
{
void (*theKernel)(int zero, int arch, u32 params);
u32 exec_at = LINUX_LOAD_BASE;
u32* p = (u32*)(LINUX_LOAD_BASE + 0x24);
if (*p != 0x016f2818)
{
puts("There is no ARM Linux zImage at the 0x81000000!\n");
return -1;
}
puts("hi");
setup_tags(); /* sets up parameters */
puts(" bye\n");
theKernel = (void (*)(int, int, u32))exec_at; /* set the kernel address */
theKernel(0, MACHINE_TYPE, PARAM_LOAD_ADDRESS_BASE); /* jump to kernel with register set */
return 0;
}
/* list of possible tags */
#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
/* structures for each atag */
struct atag_header {
u32 size; /* length of tag in words including this header */
u32 tag; /* tag type */
};
struct atag_core {
u32 flags;
u32 pagesize;
u32 rootdev;
};
struct atag_mem {
u32 size;
u32 start;
};
struct atag_videotext {
u8 x;
u8 y;
u16 video_page;
u8 video_mode;
u8 video_cols;
u16 video_ega_bx;
u8 video_lines;
u8 video_isvga;
u16 video_points;
};
struct atag_ramdisk {
u32 flags;
u32 size;
u32 start;
};
struct atag_initrd2 {
u32 start;
u32 size;
};
struct atag_serialnr {
u32 low;
u32 high;
};
struct atag_revision {
u32 rev;
};
struct atag_videolfb {
u16 lfb_width;
u16 lfb_height;
u16 lfb_depth;
u16 lfb_linelength;
u32 lfb_base;
u32 lfb_size;
u8 red_size;
u8 red_pos;
u8 green_size;
u8 green_pos;
u8 blue_size;
u8 blue_pos;
u8 rsvd_size;
u8 rsvd_pos;
};
struct atag_cmdline {
char cmdline[1];
};
struct atag {
struct atag_header hdr;
union {
struct atag_core core;
struct atag_mem mem;
struct atag_videotext videotext;
struct atag_ramdisk ramdisk;
struct atag_initrd2 initrd2;
struct atag_serialnr serialnr;
struct atag_revision revision;
struct atag_videolfb videolfb;
struct atag_cmdline cmdline;
} u;
};
#define tag_next(t) ((struct atag *)((u32 *)(t) + (t)->hdr.size))
#define tag_size(type) ((sizeof(struct atag_header) + sizeof(struct type)) >> 2)
static struct atag *params; /* used to point at the current tag */
void
setup_core_tag(u32 address,long pagesize)
{
params = (struct atag *)address; /* Initialise parameters to start at given address */
params->hdr.tag = ATAG_CORE; /* start with the core tag */
params->hdr.size = tag_size(atag_core); /* size the tag */
params->u.core.flags = 1; /* ensure read-only */
params->u.core.pagesize = pagesize; /* systems pagesize (4k) */
params->u.core.rootdev = 0; /* zero root device (typicaly overidden from commandline )*/
params = tag_next(params); /* move pointer to next tag */
}
void
setup_ramdisk_tag(u32 size)
{
params->hdr.tag = ATAG_RAMDISK; /* Ramdisk tag */
params->hdr.size = tag_size(atag_ramdisk); /* size tag */
params->u.ramdisk.flags = 0; /* Load the ramdisk */
params->u.ramdisk.size = size; /* Decompressed ramdisk size */
params->u.ramdisk.start = 0; /* Unused */
params = tag_next(params); /* move pointer to next tag */
}
void
setup_initrd2_tag(u32 start, u32 size)
{
params->hdr.tag = ATAG_INITRD2; /* Initrd2 tag */
params->hdr.size = tag_size(atag_initrd2); /* size tag */
params->u.initrd2.start = start; /* physical start */
params->u.initrd2.size = size; /* compressed ramdisk size */
params = tag_next(params); /* move pointer to next tag */
}
void
setup_mem_tag(u32 start, u32 len)
{
params->hdr.tag = ATAG_MEM; /* Memory tag */
params->hdr.size = tag_size(atag_mem); /* size tag */
params->u.mem.start = start; /* Start of memory area (physical address) */
params->u.mem.size = len; /* Length of area */
params = tag_next(params); /* move pointer to next tag */
}
unsigned
strlen(const char* p)
{
unsigned l = 0;
while(*p++)
++l;
return l;
}
void
memcpy(char* dst, const char* src, unsigned len)
{
while(len--)
*dst++ = *src++;
}
void
setup_cmdline_tag(const char *line)
{
int linelen;
linelen = strlen(line);
if(!linelen)
return; /* do not insert a tag for an empty commandline */
params->hdr.tag = ATAG_CMDLINE; /* Commandline tag */
params->hdr.size = (sizeof(struct atag_header) + linelen + 1 + 4) >> 2;
memcpy(params->u.cmdline.cmdline, line, linelen + 1); /* place commandline into tag */
params = tag_next(params); /* move pointer to next tag */
}
void
setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE; /* Empty tag ends list */
params->hdr.size = 0; /* zero length */
}
extern char* command_line;
void
setup_tags()
{
setup_core_tag(PARAM_LOAD_ADDRESS_BASE, 4096); /* standard core tag 4k pagesize */
setup_mem_tag(SDRAM_BASE, SDRAM_SIZE); /* 64Mb at 0x80000000 */
setup_cmdline_tag(command_line); /* commandline setting root device */
setup_end_tag(); /* end of tags */
}
#include "imxarm11_uart.h"
int _putchar(int ch)
{
volatile PCSP_UART_REG uart = (PCSP_UART_REG)CSP_BASE_REG_PA_UART1;
while (!(uart->UTS & CSP_BITFMASK(UART_UTS_TXEMPTY)))
;
// Send the character
uart->UTXD = ch;
}
int
puts(const char *src)
{
while (*src)
_putchar(*src++);
}