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

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

NOR与NAND启动

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

  • NAND 启动自动复制到4KRAM

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

链接脚本规划

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

  1. SECTIONS {
  2. . = 0x33f80000;
  3. .text : { *(.text) }
  4. . = ALIGN(4);
  5. .rodata : {*(.rodata*)}
  6. . = ALIGN(4);
  7. .data : { *(.data) }
  8. . = ALIGN(4);
  9. __bss_start = .;
  10. .bss : { *(.bss) *(COMMON) }
  11. __bss_end = .;
  12. }

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

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

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

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

初始化规划


  1. #define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
  2. #define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
  3. #define MEM_CTL_BASE 0x48000000
  4. .text
  5. .global _start
  6. _start:
  7. /* 1. 关看门狗 */
  8. ldr r0, =0x53000000
  9. mov r1, #0
  10. str r1, [r0]
  11. /* 2. 设置时钟 */
  12. ldr r0, =0x4c000014
  13. // mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
  14. mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
  15. str r1, [r0]
  16. /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
  17. mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
  18. orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
  19. mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
  20. /* MPLLCON = S3C2440_MPLL_200MHZ */
  21. ldr r0, =0x4c000004
  22. ldr r1, =S3C2440_MPLL_400MHZ
  23. str r1, [r0]
  24. /* 启动ICACHE */
  25. mrc p15, 0, r0, c1, c0, 0 @ read control reg
  26. orr r0, r0, #(1<<12)
  27. mcr p15, 0, r0, c1, c0, 0 @ write it back
  28. /* 3. 初始化SDRAM */
  29. ldr r0, =MEM_CTL_BASE
  30. adr r1, sdram_config /* sdram_config的当前地址 */
  31. add r3, r0, #(13*4)
  32. 1:
  33. ldr r2, [r1], #4
  34. str r2, [r0], #4
  35. cmp r0, r3
  36. bne 1b
  37. /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
  38. ldr sp, =0x34000000
  39. bl nand_init
  40. mov r0, #0
  41. ldr r1, =_start
  42. ldr r2, =__bss_start
  43. sub r2, r2, r1
  44. bl copy_code_to_sdram
  45. bl clear_bss
  46. /* 5. 执行main */
  47. ldr lr, =halt
  48. ldr pc, =main
  49. halt:
  50. b halt
  51. sdram_config:
  52. .long 0x22011110 //BWSCON
  53. .long 0x00000700 //BANKCON0
  54. .long 0x00000700 //BANKCON1
  55. .long 0x00000700 //BANKCON2
  56. .long 0x00000700 //BANKCON3
  57. .long 0x00000700 //BANKCON4
  58. .long 0x00000700 //BANKCON5
  59. .long 0x00018005 //BANKCON6
  60. .long 0x00018005 //BANKCON7
  61. .long 0x008C04F4 // REFRESH
  62. .long 0x000000B1 //BANKSIZE
  63. .long 0x00000030 //MRSRB6
  64. .long 0x00000030 //MRSRB7

参数设置

  1. nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
  2. setup_start_tag();
  3. setup_memory_tags();
  4. setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
  5. setup_end_tag();
  6. void setup_start_tag(void)
  7. {
  8. params = (struct tag *)0x30000100;
  9. params->hdr.tag = ATAG_CORE;
  10. params->hdr.size = tag_size (tag_core);
  11. params->u.core.flags = 0;
  12. params->u.core.pagesize = 0;
  13. params->u.core.rootdev = 0;
  14. params = tag_next (params);
  15. }

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

  1. theKernel = (void (*)(int, int, unsigned int))0x30008000;
  2. theKernel(0, 362, 0x30000100);

简单BootLoader的更多相关文章

  1. ucore-lab1-练习1report

    练习1 report 问题1:OS镜像文件ucore.img是如何一步一步生成的(需要比较详细地解释Makefile中的每一条相关命令和命令参数的含义,以及说明命令导致的结果)? GNU make是一 ...

  2. stm32最简单的实现BootLoader

    BootLoader大家应该都知道是干什么的,简单的来说就是程序开始运行前的一段程序. 在成熟的产品中,通常都是采用BootLoader方式来升级产品的程序.也就是IAP升级.在了解完基本的实现原理后 ...

  3. 最简单的bootloader的编写

    目标:写出bootloader的第一阶段代码和第二阶段代码,并测试. 最简单的bootloader的编写步骤: 1. 初始化硬件:关看门狗.设置时钟.设置SDRAM.初始化NAND FLASH2. 如 ...

  4. Android Bootloader LittleKernel的两篇文章 【转】

    转自:http://blog.csdn.net/loongembedded/article/details/41747523 2014-12-05 14:37 3599人阅读 评论(2) 收藏 举报 ...

  5. Xmodem Bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 多年前玩Cisco交换 ...

  6. 自己用C语言写单片机PIC16 serial bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 为什么自己写bootl ...

  7. PyInstaller 安装方法 及简单的编译exe (python3)

    安装PyInstaller //地址 https://github.com/pyinstaller/pyinstaller/tree/python3 //上面的链接已经失效,新的(20160809更) ...

  8. bootloader(转)

    本文详细地介绍了基于嵌入式系统中的 OS 启动加载程序 ―― Boot Loader 的概念.软件设计的主要任务以及结构框架等内容. 1. 引言在专用的嵌入式板子运行 GNU/Linux 系统已经变得 ...

  9. BootLoader 详解(3)

    BootLoader的stage2 stage2的代码是C语言来实现的,以便于实现更复杂的功能和取得更好的代码可读性和移植性.它与普通C语言程序不同的是,在编译和链接BootLoader这样的程序时, ...

随机推荐

  1. 最简单的socket服务器与客户端

    服务器: //服务器 #include <stdio.h> #include <netinet/in.h> #include <unistd.h> #include ...

  2. Codeforces 714A 朋友聚会

    参考自:https://www.cnblogs.com/ECJTUACM-873284962/p/6395268.html A. Meeting of Old Friends time limit p ...

  3. POJ1015-Jury Compromise-dp

    略复杂的dp题. 有n个人,每个人有两个分数di,pi.从中选出m个人,要求|sigma(di)-sigma(pi)|最小,相同时则输出sigma(di)+sigma(pi)最大的情况. 答案完整输出 ...

  4. 二分图最小点覆盖König定理的简单证明 (加入自己理解)

    第一次更改:http://blog.sina.com.cn/s/blog_51cea4040100h152.html 讲的更细致 增广路:https://blog.csdn.net/qq_374572 ...

  5. BZOJ 4326 运输计划

    二分答案+树链剖分+树上差分 我们假设x是最小的花费,可以想到给定x,所有运输计划中花费大于x的计划必须经过虫洞,且最长的一条的花费减去虫洞所在边的花费要小于等于x 那么对于x,虫洞所在的位置肯定是确 ...

  6. Appium-desktop安装启用Inspector一直报错An unknown server-side error occurred...

    遇到的问题是: 启用Appium-desktop的Inspector一直报错:An unknown server-side error occurred while processing the co ...

  7. 【XSY1762】染色问题 网络流

    题目描述 给定一张\(n\)个点\(m\)条边的无向图.每个顶点有一个颜色,要么是黑,要么是白.我们想进行一些操作,使得最终每一条边的两个端点都是不同的颜色.每一次操作,你可以将一条边的两个端点交换颜 ...

  8. SCOI 2015 Day2 简要题解

    「SCOI2015」小凸玩密室 题意 小凸和小方相约玩密室逃脱,这个密室是一棵有 $ n $ 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 $ A_i $,每条边 ...

  9. Android RadioGroup中设置默认选中RadioButton 后,选中两个的问题 解决方法

    项目中遇到多个RadioGroup中单选RadioButton ,设置了默认选中第一个 . 然后就 能选中两个RadioButton . . .. 我开始这样给设置默认选中一个的: for (int ...

  10. 【BZOJ4008】[HNOI2015]亚瑟王(动态规划)

    [BZOJ4008][HNOI2015]亚瑟王(动态规划) 题面 BZOJ 洛谷 题解 设\(f[i][j]\)表示前\(i\)张卡中有\(j\)张被触发的概率. 分两种情况转移,即当前这张是否被触发 ...