UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor crprzyby
Visitor
6,775 Views
Registered: ‎05-14-2009

linux relocation

Ive been working with an existing xilinx design on the virtex405-ml405 and migrating to the latest 2.6.29 kernel image.  Currently Im just trying to get the device to boot the kernel from the mtd boot partion.  If we load the .elf kernel through the xilinx tool kit it works fine.  But if we take the binary image and store it on the mtd device it fails during startup.

 

zImage starting: loaded at 0x00000000 (sp: 0x0017beb0)
Allocating 0x32c629 bytes for kernel ...
Insufficient memory for kernel at address 0! (_start=00000000, uncompressed size=0030dee8)

 

It looks as though the kernel load address is not setup correctly.  In the previous 2.6.9 kernel there was the CONFIG_BOOT_LOAD=0x00400000 option, however, this looks to be deprecrated in 2.6.29.  Anyone know what the new kernel options are for this?  

 

I noted a  PHYSICAL_START option but that is only available for FSL_BOOKE.

 

Any thoughts or suggestions would be appreciated

--Carl Przybylek 

 

 

 

 


 

0 Kudos
5 Replies
Xilinx Employee
Xilinx Employee
6,773 Views
Registered: ‎04-23-2008

Re: linux relocation

I'm not sure that the present ARCH=powerpc simpleImage executable can relocate itself from flash (though I have not actually tried it).  I have, however, written a simple standalone BSP application which will copy a simpleImage to the memory it was linked to and jump to that. There is also an accompanying perl script to convert the simpleImage to binary (suitable for flash programming) and prepends a few words for the BSP apllication (so it knows where to copy, and how many bytes to copy).

 

Here are the pertinent bits (they are unofficial and unsupported):

 

------------

$ cat loader.c

/*

 * Brian Hill

 * Xilinx, Inc.

 * April, 2009

 */
#include <xuartns550_l.h>
#include <xparameters.h>
#include <xstatus.h>
#include <stdio.h>
#include <string.h>

#define UART_BASEADDR XPAR_UARTNS550_0_BASEADDR
#define UART_CLOCK    XPAR_UARTNS550_0_CLOCK_FREQ_HZ
#define UART_BAUDRATE 9600

#define FL_HEADER_OFFSET 0x00400000 /* /dev/mtd1 */
#define FL_HEADER_ADDR   (XPAR_EMC_0_MEM0_BASEADDR + FL_HEADER_OFFSET)
#define FLASH_COOKIE "XLNX"

struct fl_header
{
    char      cookie[4];
    unsigned *entry;
    unsigned *bss;
    unsigned  bss_size;
    unsigned *load_addr;
    unsigned  load_size;
    unsigned  text[];
};
typedef struct fl_header * fl_header_t;

int main()
{
    fl_header_t fl_header;
    unsigned   *dest, *src, size;
    void (*fp)();

    fl_header = (fl_header_t)FL_HEADER_ADDR;

    XUartNs550_SetBaud(UART_BASEADDR, UART_CLOCK, UART_BAUDRATE);
    XUartNs550_mSetLineControlReg(UART_BASEADDR, XUN_LCR_8_DATA_BITS);

    xil_printf("Xilinx Loader:\n\r");
    xil_printf("Flash header at: 0x%08x\n\r", (unsigned)fl_header);
    if (strncmp(fl_header->cookie, FLASH_COOKIE, sizeof(int)) != 0) {
        xil_printf("\n\rInvalid flash header; halted.\n\r");
        while (1) { ; }
    }
    xil_printf("Entry:     0x%08x\n\r", fl_header->entry);
    xil_printf("BSS:       0x%08x\n\r", fl_header->bss);
    xil_printf("BSS Size:  0x%08x\n\r", fl_header->bss_size);
    xil_printf("Load Addr: 0x%08x\n\r", fl_header->load_addr);
    xil_printf("Load Size: 0x%08x\n\r", fl_header->load_size);
   
    xil_printf("Zero BSS:\n\r");
    bzero(fl_header->bss, fl_header->bss_size);

    xil_printf("Copy text:\n\r");
    memcpy(fl_header->load_addr, fl_header->text, fl_header->load_size);

    xil_printf("Launch:\n\r");
    fp = (void *)fl_header->entry;
    (*fp)();
}


----------

 

$ cat build_rom.pl
#!/usr/bin/perl
#
# Brian Hill
# Xilinx, Inc.
# April, 2009
#
# Output file format:
# Word : Value
# 0      "XLNX"
# 1      Entry point address
# 2      BSS address
# 3      BSS size
# 4      Load address
# 5      Load size
# 6      kernel image
#

if ($#ARGV != 0) {
    print "Generate flash image from and ELF file. \n";
    print "EXAMPLE: Genereate zImage.initrd.bin : \n";
    print "$0 zImage.initrd\n";
    exit (1);
}

# $input_elf = "zImage.initrd";
$input_elf = $ARGV[0];

open(OUTFILE, ">$input_elf.bin");
$a = "XLNX";
print OUTFILE $a;

print "Parsing readelf output for $input_elf\n";
# Parse the output of readelf for the indicated ELF file to pluck out
# the necessary header info.
@lines = `readelf -e $input_elf`;
foreach $line (@lines) {
    if (($addr) = $line =~ /Entry point address:\s+(\w+)/ ) {
        print "Entry: $addr\n";
        $a = pack('N', hex($addr));
        print OUTFILE $a;
    }
    if (($addr, $size) = $line =~ /.bss\s+NOBITS\s+(\w+) \w+ (\w+) \w+/) {
        printf "BSS:   0x%08x %d\n",  hex($addr), hex($size);
        $a = pack('N', hex($addr));
        print OUTFILE $a;
        $a = pack('N', hex($size));
        print OUTFILE $a;
    }
    if (($addr, $size) = $line =~ /LOAD\s+\w+ (\w+) \w+ (\w+) /) {
        print "LOAD:  $addr $size\n";
        $a = pack('N', hex($addr));
        print OUTFILE $a;
        $a = pack('N', hex($size));
        print OUTFILE $a;
    }
}

close($OUTFILE);

print "Generating image:\n";
`powerpc-eabi-objcopy -O binary $input_elf tmp.bin`;
print "Appending header:\n";
`cat tmp.bin >> $input_elf.bin`;
`rm tmp.bin`;
0 Kudos
Visitor crprzyby
Visitor
6,711 Views
Registered: ‎05-14-2009

Re: linux relocation

So back in linux 2.6.9 there is some assembly code in arch/ppc/boot/simple/relocation.S that moves the memory up to 0x00400000 and unpacks the kernel from there.  Any thoughts on if this code would be portable to the 2.6.29 kernel and the simpleImage boot wrapper? 

 

Also, Ive looked around to more information on binary/elf format and the conversions, and haven't really found an answer to this question.  If the .text section is set to 0x00400000 in the elf header and then then code is converted to binary format, how does the conversion maintain this  assignment.  Say for instance the .globl(_zImage_start) in the head.S would print out 0x00400000 if you printed the address of the symbol in elf?  would the resulting binary image do the same?  Ive been unable to find any good articles describing the elf->binary conversion process.  Any thoughts or links would be appreciated.

 

--Carl Przybylek 

0 Kudos
Xilinx Employee
Xilinx Employee
6,709 Views
Registered: ‎04-23-2008

Re: linux relocation

I believe you are correct; I think with ARCH=ppc it was possible to directly boot a zImage from flash.  ARCH=ppc is deprecated however, and the present simpleImage from ARCH=powerpc no longer natively supports this.  The start address 0x00400000 is less fixed in the present build; it is decided by the linker.  I.E. if you have a really big kernel you could find your loader automagically links at 0x00800000 instead.

 

The old zImages would have a branch instruction at the very end (which jumped to _start) - you could program the image right at the boot vector (assuming flash was mapped at the very to of address space).  The blobbing on of device trees on the end of the image is propbably why this is presently busto.

 

object copy produces a binary image suitable for programming into flash. There is no 'hole' at the beginning (if the text starts at 0x00400000 then this will appear at offset 0x00000000 in the file -- you are responsible for the initial 'relocation'). Depending on how the application code and data are laid out you could have a very LARGE binary file however.  If, for example, there are two text segments far apart in the address space, this 'hole' between them would be lots of worthless space in the binary file.  This isn't a problem with loader simpleImage ELFs presently.

 

-Brian

0 Kudos
Visitor crprzyby
Visitor
6,696 Views
Registered: ‎05-14-2009

Re: linux relocation

 

Ok, so I was looking back at your BSP and seeing if I could incorporate that BSP with the stage1_loader from memec that is being used with the 2.6.9 kernel.  Currently it looks like our base flash is at 0x50000000.  The stage1_loader simply copies 0x00400000 bytes from that location to 0x0, filling up our memory with whatever was on the flash, and then executes at 0x00 ( boot = (int (*) (void)) (0x00); boot(); )

 

 Im assuming there is some mapping for our flash at 0x00400000 or the previous kernel's relocation would not work.  Would it be safe to assume I could simply add another option to the stage1_loader that utilized the technique you specified in your previous post?   We would still need the older boot code to handle the legacy code on the 2.6.9 kernel.

  

Lastly, I was slightly confused by the last portion of fixing up the kernel for use with the BSP.  Would the following need to be reversed, with the header data being prepended to the kernel instead of added to the end?

 

 print "Appending header:\n";
`cat tmp.bin >> $input_elf.bin`;

 

 

 Thanks again!!  I haven't done alot of work with customized boot loaders, so thanks for all your help with sorting through all this.

  

 

>> DTS info

 

        DDR_SDRAM_32Mx16: memory@0 {
                device_type = "memory";
                reg = < 0x0 0x4000000 >;
        } ;

                    .......

     

                        FLASH_4Mx16: flash@50000000 {
                                bank-width = <2>;
                                compatible = "xlnx,opb-emc-2.00.a", "cfi-flash";                                reg = < 0x50000000 0x4000000 >;

 

                    .......

   

 

>> readelf -e output from kernel

 

Entry point address:   0x400000 

 

[ 6] .bss         NOBITS          00569000 178a3d 00eeec 

 

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align 

LOAD           0x010000 0x00400000 0x00400000 0x168a3d 0x177eec  

 

 >> Stage1 loader output

 

Stage 1 Boot Loader
Version 8649A509 Built:  Nov 18 2008 18:10:58

UBoot start address = 0x0
 

Using Flash at location 50000000
Testing for a supported flash device
Manufacturer = 00000089 = Intel
Device       = 0000891C = PC28F256P30
Supported flash found at address 50000000
 

0 Kudos
Xilinx Employee
Xilinx Employee
6,693 Views
Registered: ‎04-23-2008

Re: linux relocation

With the flash at 0x50000000 you pretty much must have a loader (such as my previous post) in BRAM, as 0x50000000 is not at the processor boot vector. This is probably easier for debugging your loader, but in a final system you might just want to map the flash so that it falls at the boot vector (the flash address map ends at 0xFFFFFFFC) so that you don't need to use FPGA resources with the BRAM.

 

If you were to use the scheme in my post there would be essentialy 3 pieces of software.  The simple loader using the standalone BSP, the simpleImage loader that decompresses the kernel, and the kernel itself. Regarding what gets copied where, the ARCH=ppc zImage (or ARCH=powerpc simpleImage, etc...) would be copied from flash to it's linked address (perhaps 0x00400000) by code running in BRAM (the top of addressable memory).  The loader in BRAM then jumps to  the simpleImage _start in RAM where it was just copied to.  Software then decompresses the kernel (vmlinux) and copies it to 0x00000000 and branches to it.  One of the first things the kernel  does is enable the MMU so that memory at 0x00000000 has the virtual address of 0xC0000000.

 

I believe a zImage has code to copy itself from flash to the linked addres in RAM (it is position independent code) if it finds it is executing at a different address, but I've never tried it personnally.  

 

> Lastly, I was slightly confused by the last portion of fixing up the kernel for use with the BSP.  Would the following need to be reversed, with the header data

> being prepended to the kernel instead of  added to the end?

>

> print "Appending header:\n";
>`cat tmp.bin >> $input_elf.bin`;

 

The comment I chose to print is not accurate (but it sounded better than the truth).  It would be more accurate to say "appending kernel image to header" as the header is at the beginning, not the end.

 

-Brian

0 Kudos