Search

Technical Discussion Group Forum

This forum is provided for user discussion. While Beacon EmbeddedWorks support staff and engineers participate, Beacon EmbeddedWorks does not guarantee the accuracy of all information within in the Technical Discussion Group (TDG).

The "Articles" forums provide brief Articles written by Beacon EmbeddedWorks engineers that address the most frequently asked technical questions.

To receive email notifications when updates are posted for a Beacon EmbeddedWorks product download, please subscribe to the TDG Forum of interest.

TDG Forum

PrevPrev Go to previous topic
NextNext Go to next topic
Last Post 16 Oct 2007 12:16 PM by  messenger
Getting kernel command line parameters from Lolo into Linux
 2 Replies
Sort:
You are not authorized to post a reply.
Author Messages
mcelweep@msoe.edu
New Member
New Member
Posts:


--
23 Aug 2007 11:54 AM
    I have been struggling to get the Logicloader bootloader to load in my image and have been encountering a frustrating issue. I want to take in kernel command arguments for Lolo to configure the video frame buffer characteristics (i.e. hsync, vsync, pixel clock, etc.). The problem is that when I specify the command line arguments in Lolo they don't get passed to the kernel. I have found the documentation for the exec command and here is what it says:

    Quote:
    The ‘exec’ Command
    The ‘exec’ command is an assembly-level jump to the starting instruction of a program that will pass in three arguments. If ‘exec’ is executed without a parameter, LogicLoader will jump to the program start address of the last program loaded to system RAM (if any) and pass in a pointer to an empty string. If both an address and command line are specified, the ‘exec’ command will jump to the specified address and pass a pointer to the command line provided. The ‘exec’ command will disable interrupts, the cache, and the MMU (if present) prior to executing the jump. The ‘exec’ command passes the command line argument via a pointer to memory that has been allocated from LogicLoader’s heap. Any application or OS code must preserve the command line, or finish using the command line arguments, before reclaiming LogicLoader’s memory space for its own use. Because the ‘exec’ command shuts off the MMU, the image must have a virtual address that maps directly to its physical address since the entry address that ‘exec’ jumps to will always be a physical address. This example may be used when writing a function that LogicLoader will exec to:

    int my_exec_function(unsigned int arg1, unsigned int arg2, char *cmd_string);

    The first two arguments have fixed values for legacy reasons: arg1 = 0, and arg2 = 997. The third argument will be a pointer to the command line as described above.


    So what I thought I would have to do is change the function that gets called on kernel start to have the signature called out by this exec command. After digging through the kernel, I thought that asm_linkage void __init start_kernel(void) in /init/main.c is the function that I need to change. So I changed it and my image will no longer boot. Are there any funky configuration options that need to be enabled to do this? Is there some code in the /arch/m68knommu/kernel/entry.S that calls the start_kernel function? Is what I am trying to do possible? Has anyone had any luck dealing with this?
    paulc@logicpd.com
    New Member
    New Member
    Posts:


    --
    27 Sep 2007 09:57 PM
    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++);
    }


    messenger
    New Member
    New Member
    Posts:


    --
    16 Oct 2007 12:16 PM
    Thanks for the reply,

    I have decided to just change the kernel to look at 0x5000 (or was it 0x50000 where non lolo code started?) and I have a format script that burns a set of video options into that location. A bit of a hack, but it works pretty well, (and it wouldn't be the first hack to make it into the kernel <!-- s:-P -->:-P<!-- s:-P --> )
    You are not authorized to post a reply.