linux/android memory/flash layout

通常做bootloader和kernel的人都会对memory layout感兴趣,最近修改了一次memory/flash layout,先记录下来:

1.flash layout

   flash layout是rom的分布图,通常直接看partion table就能直接明了。

2.memory layout

   通常android下memory 可能分成以下几个部分:

   bootloader/kernel/share memory。

   目前memory一共2个G,划分如下:

    1)0M~64M(0x4000000) reserver for Trustzoom 

    2)64M~72M(0x4800000) reserver for later use 

    3) 72M~73M(0x4900000) for sysinit 

    4) 73M~79M(0x4f00000) for ZSP 

    5)79M~80M(0x50000000) for bootloader

    6)80M~1360M(0x55000000) for kernel

    7)1360M~2048M end for SHM 

1)是ARM TZ加密安全内核,可以看作一个kernel

2)中的64-66M用于sys_init加载bootloader,66-72M用于bootloader加载logo等,原因:eg,在bootloader中没有malloc函数,

   所以在读取flash上的logog等分区数据时,直接保存到指定内存地址。

3)5)是bootloader部分.

4)用于ARM TZ加密内核其他部分

 

因此在非安全启动的时候,启动流程是3)-> 5)  ->  6)

 

2.1 修改sysinit、bootloader的memory

 

在修改sysinit、bootloader的memory时,其实就是修改各自的 .lds

eg,bootloader.lds

 26 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 27 OUTPUT_ARCH(arm)
 28 ENTRY(BootLoaderEntry)
 29 SECTIONS
 30 {
 31         . = 0x04200000;
 32        
__bootloader_buf_start = .;
 33
 34         . = 0x04F00000;
 35         . = ALIGN(0x4000);
 36         __ttb_base_start = .;

              .......

 75         . = 0x05000000;
 76         . = ALIGN(4);
 77         __irq_stack_start = .;
 78 }

   在前面2)中定义memory 66M(0x04200000)-72M用于bootloader读取flash logo等分区的数据存储,所以直接在lds中定义了__bootloader_buf_start,然后在bootloader中直接使用这个内存变量:

extern int __bootloader_buf_start;

#define BOOTLOADER_BUF_ADDR      ((unsigned int)(&__bootloader_buf_start))

下面34行修改bootloader的加载内存地址为79M(0x4F00000),75行结束地址为80M。

sys_init如同bootloader。

 

2.2 改kernel的memory地址

 

        如果启动的是android,那么首先要修改的是BoardConfig.mk中的

       BOARD_KERNEL_BASE := 0x05000000(79M)

   因为linux kernel和ramdisk在android中会被打包到boot.img中,并且会给boot.img加一个头:

system/core/mkbootimg$ vi bootimg.h

 28 struct boot_img_hdr
 29 {
 30     unsigned char magic[BOOT_MAGIC_SIZE];
 31
 32     unsigned kernel_size;  /* size in bytes */
 33     unsigned kernel_addr;  /* physical load addr */
 34
 35     unsigned ramdisk_size; /* size in bytes */
 36     unsigned ramdisk_addr; /* physical load addr */
 37
 38     unsigned second_size;  /* size in bytes */
 39     unsigned second_addr;  /* physical load addr */
 40
 41     unsigned tags_addr;    /* physical addr for kernel tags */
 42     unsigned page_size;    /* flash page size we assume */
 43     unsigned unused[2];    /* future expansion: should be 0 */
 44
 45     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
 46
 47     unsigned char cmdline[BOOT_ARGS_SIZE];
 48
 49     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
 50 };

                              +----------------------+

                              |  boot header       | 1 page

                              +----------------------+

                              |    kernel                | n pages

                              +----------------------+

                              |    ramdisk            | m pages

                              +----------------------+

                              |   second stage   | o pages

                              +----------------------+

boot.img结构就是上面的样子。

    bootloader或uboot在加载kernel时会先去读这个头,而这个头中kernel_addr就是BoardConfig.mk中定义的:

BOARD_KERNEL_BASE := 0x05000000

当然也可以不定义这个变量那么kernel_addr默认为0x01000000.

bootloader中读到这个值之后将会把它赋值给TheKernel函数,从而可以正常去加载解压内核。

 

    然后修改linux,如果kernel是atags启动的需要修改bootloader的memory size参数,还要记得ramdisk参数。

    是dts启动就不需要,只要在dts中修改linux的可用内存为79M~1360M,share memory为1360M~2048M :

@@ -62,7 +62,7 @@
        memory {
                name = "memory";
                device_type = "memory";
-               reg = <0x01000000 0x55000000>;
+               reg = <0x05000000 0x55000000>;
        };

        chosen {
@@ -419,7 +419,7 @@

                shm@69000000 {
                        compatible = "mrvl,berlin-shm";
-                       reg = <0x56000000 0x2a000000>, <0x80000000 0x0>;
+                       reg = <0x5A000000 0x26000000>, <0x80000000 0x0>;
                };

由于kernel是压缩的所以刚才80M的地址是未解压kernel的内存地址不一定是kernel的真正运行地址,我把其运行地址也改为80M:

修改linux config文件:

 

- CONFIG_PHYS_OFFSET=0x01000000

+ CONFIG_PHYS_OFFSET=0x05000000

 

如果CONFIG_PHYS_OFFSET没有定义,也就可以不修改了,但是前提是配置了ARM_PATCH_PHYS_VIRT and AUTO_ZRELADDR,只要满足对齐条件:

因为linux/arch/arm$ vi boot/compressed/head.S中

 

 170 #ifdef CONFIG_AUTO_ZRELADDR
 171                 @ determine final kernel image address
 172                 mov     r4, pc
 173                 and     r4, r4, #0xff000000
 174                 add     r4, r4, #TEXT_OFFSET
 175 #else
 176                 ldr     r4, =zreladdr
 177 #endif

 

可以看到如果定义了CONFIG_AUTO_ZRELADDR,则按照要求地址对齐的方式去加载内核,否者使用zreladdr,zreladdr就是在Makefile.boot:

  CONFIG_PHYS_OFFSET + 0x8000得到的。

然而如果定义了CONFIG_AUTO_ZRELADDR,这表示只要地址按照一定方式对齐即可,eg:

and     r4, r4, #0xff000000
表示16M对齐,#0xfff00000则是1M对齐。

 

最后有一个疑问:为什么我见过的板子都是默认16M对齐的,比如三星也是0x01000000,高通 、marvell也是16M对齐,其实我试过不是16M对齐也可以启动。

下面的提交可能说明了这个问题:

commit dc21af99fadcfa0ae65b52fd0895f85824f0c288
Author: Russell King <
rmk+kernel@arm.linux.org.uk>
Date:   Tue Jan 4 19:09:43 2011 +0000

    ARM: P2V: introduce phys_to_virt/virt_to_phys runtime patching

    This idea came from Nicolas, Eric Miao produced an initial version,
    which was then rewritten into this.

有如下代码和解释:

+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+
+/* __fixup_pv_table - patch the stub instructions with the delta between
+ * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
+ * can be expressed by an immediate shifter operand. The stub instruction
+ * has a form of '(add|sub) rd, rn, #imm'.
+ */
+       __HEAD
+__fixup_pv_table:
+       adr     r0, 1f
+       ldmia   r0, {r3-r5, r7}
+       sub     r3, r0, r3      @ PHYS_OFFSET - PAGE_OFFSET
+       add     r4, r4, r3      @ adjust table start address
+       add     r5, r5, r3      @ adjust table end address
+       str     r8, [r7, r3]!   @ save computed PHYS_OFFSET to __pv_phys_offset
+       mov     r6, r3, lsr #24 @ constant for add/sub instructions
+       teq     r3, r6, lsl #24 @
must be 16MiB aligned
+       bne     __error
+       str     r6, [r7, #4]    @ save to __pv_offset
+       b       __fixup_a_pv_table

到这就修改完了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值