zoukankan      html  css  js  c++  java
  • 简单BootLoader


    title: 简单BootLoader
    tags: linux
    date: 2018-09-28 23:23:05

    简单BootLoader

    概述

    目标: 启动内核,也就是需要读取内核到内存,也就是操作flash和内存

    一个最基本的BootLoader应该有以下步骤:

    1. 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
    2. 如果bootloader比较大,要把它重定位到SDRAM
    3. 把内核从NAND FLASH读到SDRAM
    4. 设置要传给内核的参数
    5. 跳转执行内核

    优化: 为了加快运行速度,应该提高主频,打开Icach

    	/* 启动ICACHE */
    	mrc p15, 0, r0, c1, c0, 0	@ read control reg
    	orr r0, r0, #(1<<12)
    	mcr	p15, 0, r0, c1, c0, 0   @ write it back
    

    NOR与NAND启动

    参考文档 ARM裸机>启动流程

    • NAND 启动自动复制到4KRAM

    • NOR启动,片内RAM为0x4000,0000

      mark

    链接脚本规划

    我们从上图可以看到,SDRAM的起始地址为0x3000,0000,SDRAM大小为64M,也就是地址顶端为0x3400,0000.预留512K给Bootloader,也就是规划hex(0x34000000-512*1024)=0x33f8,0000为Bootloader的起始地址.链接脚本考虑字节对齐.

    SECTIONS {
        . = 0x33f80000;
        .text : { *(.text) }
        
        . = ALIGN(4);
        .rodata : {*(.rodata*)} 
        
        . = ALIGN(4);
        .data : { *(.data) }
        
        . = ALIGN(4);
        __bss_start = .;
        .bss : { *(.bss)  *(COMMON) }
        __bss_end = .;
    }
    

    链接脚本中有个COMMON段,这是未初始化的全局变量,一般情况下也是直接在链接阶段放在bss段进行清零.但是注意未初始化的全局变量与初始化为0的全局变量,并不对等.[未初始化的全局变量(COMMON段)为弱符号,如果有同名的全局变量,可能会存在覆盖的情况]

    对于全局变量来说,如果初始化了不为0的值,那么该全局变量则被保存在data段,如果初始化的值为0,那么将其保存在bss段,如果没有初始化,则将其保存在common段,等到链接时再将其放入到BSS段。关于第三点不同编译器行为会不同,有的编译器会把没有初始化的全局变量直接放到BSS段。

    链接脚本中值的获取,具体参考./链接脚本.md

    //汇编方法1
    .global _bss_start
    _bss_start:
    	.word __bss_start
    ldr r1, _bss_start	//读取内存,这里是读取label所在内存的数据
    //汇编方法2
    ldr r1, =__bss_start
    //C方法
    extern int __bss_start;
    int val =&__bss_start;	//!< 获得__bss_start的值
    

    初始化规划

    
    #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
    #define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
    #define MEM_CTL_BASE    0x48000000
    
    .text
    .global _start
    _start:
    
    /* 1. 关看门狗 */
    	ldr r0, =0x53000000
    	mov r1, #0
    	str r1, [r0]
    
    /* 2. 设置时钟 */
    	ldr r0, =0x4c000014
    	//	mov r1, #0x03;			  // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
    	mov r1, #0x05;			  // FCLK:HCLK:PCLK=1:4:8
    	str r1, [r0]
    
    	/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
    	mrc	p15, 0, r1, c1, c0, 0		/* 读出控制寄存器 */ 
    	orr	r1, r1, #0xc0000000			/* 设置为“asynchronous bus mode” */
    	mcr	p15, 0, r1, c1, c0, 0		/* 写入控制寄存器 */
    
    	/* MPLLCON = S3C2440_MPLL_200MHZ */
    	ldr r0, =0x4c000004
    	ldr r1, =S3C2440_MPLL_400MHZ
    	str r1, [r0]
    
    	/* 启动ICACHE */
    	mrc p15, 0, r0, c1, c0, 0	@ read control reg
    	orr r0, r0, #(1<<12)
    	mcr	p15, 0, r0, c1, c0, 0   @ write it back
    
    
    /* 3. 初始化SDRAM */
    	ldr r0, =MEM_CTL_BASE
    	adr r1, sdram_config     /* sdram_config的当前地址 */
    	add r3, r0, #(13*4)
    1:
    	ldr r2, [r1], #4
    	str r2, [r0], #4
    	cmp r0, r3
    	bne 1b
    
    /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
    	ldr sp, =0x34000000
    
    	bl nand_init
    
    	mov r0, #0
    	ldr r1, =_start
    	ldr r2, =__bss_start
    	sub r2, r2, r1
    	
    	bl copy_code_to_sdram
    	bl clear_bss
    	
    /* 5. 执行main */
    	ldr lr, =halt
    	ldr pc, =main
    halt:
    	b halt
    
    sdram_config:
    	.long 0x22011110	 //BWSCON
    	.long 0x00000700	 //BANKCON0
    	.long 0x00000700	 //BANKCON1
    	.long 0x00000700	 //BANKCON2
    	.long 0x00000700	 //BANKCON3  
    	.long 0x00000700	 //BANKCON4
    	.long 0x00000700	 //BANKCON5
    	.long 0x00018005	 //BANKCON6
    	.long 0x00018005	 //BANKCON7
    	.long 0x008C04F4	 // REFRESH
    	.long 0x000000B1	 //BANKSIZE
    	.long 0x00000030	 //MRSRB6
    	.long 0x00000030	 //MRSRB7
    
    
    

    参数设置

    nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
    setup_start_tag();
    setup_memory_tags();
    setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
    setup_end_tag();
    
    void setup_start_tag(void)
    {
    	params = (struct tag *)0x30000100;
    
    	params->hdr.tag = ATAG_CORE;
    	params->hdr.size = tag_size (tag_core);
    
    	params->u.core.flags = 0;
    	params->u.core.pagesize = 0;
    	params->u.core.rootdev = 0;
    
    	params = tag_next (params);
    }
    

    内核存储在0x60000+64,读取到运行地址0x30008000,参数存储在0x30000100,最后传入机器ID=362

    theKernel = (void (*)(int, int, unsigned int))0x30008000;
    theKernel(0, 362, 0x30000100);  
    
  • 相关阅读:
    go包之logrus显示日志文件与行号
    linux几种快速清空文件内容的方法
    (转)CSS3之pointer-events(屏蔽鼠标事件)属性说明
    Linux下source命令详解
    控制台操作mysql常用命令
    解决beego中同时开启http和https时,https端口占用问题
    有关亚马逊云的使用链接收集
    favicon.ico--网站标题小图片二三事
    js获取url协议、url, 端口号等信息路由信息
    (转) Golang的单引号、双引号与反引号
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10023691.html
Copyright © 2011-2022 走看看