Tuesday, March 2, 2010

How is romfs moved above .bss in uClinux?

Platform: Coldfire uc5272 dev board running uClinux 2.4.x

For a ram based image, the .bss section doesn't exist in the image and has to be created by the second boot loader before kernel starts to run. Since the .bss section will be created right after .data section, taking part of the romfs' position, the romfs has to be moved up to make room before .bss is created and initialized.

The assembly file crt0_ram.S acts as the second bootloader. It takes over control from bootloader and do the actual moving of romfs. The following code snapshot is where the moving happens.

85 #ifdef CONFIG_ROMFS_FS
86 /*
87 * Move ROM filesystem above bss :-)
88 */
89 lea.l _sbss, %a0 /* Get start of bss */
90 lea.l _ebss, %a1 /* Set up destination */
91 move.l %a0, %a2 /* Copy of bss start */
92
93 move.l 8(%a0), %d0 /* Get size of ROMFS */
94 addq.l #8, %d0 /* Allow for rounding */
95 and.l #0xfffffffc, %d0 /* Whole words */
96
97 add.l %d0, %a0 /* Copy from end */
98 add.l %d0, %a1 /* Copy from end */
99 move.l %a1, _ramstart /* Set start of ram */
100
101 _copy_romfs:
102 move.l -(%a0), %d0 /* Copy dword */
103 move.l %d0, -(%a1)
104 cmp.l %a0, %a2 /* Check if at end */
105 bne _copy_romfs
106 #endif

The third longword in the romfs image is the size of itself in bytes. So after line 93, register d0 (%d0 hereafter) has the length of the whole romfs. But you may wonder why the length is added a 8 at line 94? and then the last two binary digits are zeroed out at line 95?

The comments explain it but may be too brief to get a full understanding.

As we know, when we align a memory boundary, we align it to the nearest longword position, ie, an address that is divisible by 4. By adding 4 to the address and then zeroed out the last 2 binary digits, which could be 0,1,2,3, we got the nearest longword position.

For example, when we align 0x0101, we hope it is aligned at 0x0104. 0x0101 + 4 = 0x0105, then 0x0105 AND 0xfffc = 0x0104. (it's equal to minus 1).

Then why adding 8 instead of 4 in the snapshot? Because at line 102, 103, the address is minus 4 first before a longword is moved. So we need %a0 and %a1 to point to 1 longword above the actual address.

So there may be up to 4 bytes (if the boundary is already aligned, then it's 4 bytes) that are not part of romfs but get moved. But it doesn't matter, because these extra bytes are from free memory.

No comments:

Post a Comment