Wednesday, May 5, 2010

uClinux 2.6.x ROM based image with only data, init and bss in RAM

Recently I've been trying to build a uClinux (2.6.x kernel)ROM based image for Coldfire uc5272, with the kernel executing (XIP) from within ROM, .data, .init and .bss segments in the RAM, and ROMfs as rootfs in ROM. This arrangement saves memory as only these changable parts of the system are in RAM.

There are three files to change to build such an image:
1. vmlinux.lds.S
This is the linker script file for 2.6.x kernel. It describes the memory layout of the image. The .romvec and .text segments are defined in ROM, and .data, .init, .bss segments are defined in RAM.

2. Head.S
This is the second bootloader for 2.6.x kernel. It't the entry point of the kernel. In this file, some codes are needed to move .data, .init into RAM, and clear out .bss segments.

3. uclinux.c
This is the mapping driver for ROMFS partition support. Here the starting address of romfs has to be given.

I have made all the changes, load the image into ROM, and issue a "go" command. What I got first is:

go 0x10c20000 ...

Then it just stopped there. After digging down for a while, I found the problem. The _ramend variable is 0, while it's supposed to be the end of the RAM. But I clearly set a value for it in head.S. And here is the code snap:

GET_MEM_SIZE /* macro code determines size */
addl %a7,%d0
movel %d0,_ramend /* set end ram addr */

And here is the code for moving .data, .init into RAM:

lea _etext, %a0
lea _sdata, %a1
lea _sbss, %a2
_copy_data:
movel (%a0)+, (%a1)+
cmpal %a1, %a2
bhi _copy_data

How come _ramend is 0? By the way, the logs at __log_buf (0x3df44 of RAM in my case) indicates that there was a memory access violation, which coincides a _ramend with wrong value.

The answer is really simple. But finding the answer took me some time. It turned out that the order of setting _ramend and moving .data into RAM is significant and I did it in a wrong order.

The right order is to move .data into RAM first and then set _ramend. Why? because when the image is burnt into ROM, the .data segment is in ROM, with all the variables in it have their init values. For _ramend, it's 0. But _ramend's address is actually in RAM (0x2000c in my case). So if _ramend is set before .data is moved, the set value will be over taken by the init value from ROM. So the .data needs to be moved into RAM first, then set the value for _ramend, the value will be kept and for later use.

How do I find the address of _ramend? I found it from System.map. The first 4 variables in .data segment are:

00020000 D _rambase
00020000 D _sdata
00020004 D _ramvec
00020008 D _ramstart
0002000c D _ramend

No comments:

Post a Comment