S3C2410 bootloader(vivi)阅读笔记

S3C2410 bootloader(vivi)阅读笔记,第1张

 

  建议读一读《嵌入式系统Boot Loader技术内幕》(詹荣开著)。什么是Bootloader就不再这里废话了,看看上面的文章就明了了。

  Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,redboot,lilo等等。Vivi 是韩国mizi公司专门为三星s3c2410芯片设计的Bootloader。

  先来看看vivi的源码树:

  vivi-+-arch-+-s3c2410

  |-DocumentaTIon

  |-drivers-+-serial

  | ‘ -mtd-+-maps

  | |-nor

  | ‘-nand

  |-include-+-platform

  | |-mtd

  | ‘-proc

  |-init

  |-lib-+-priv_data

  |-scripts-+-lxdialog

  |-test

  |-uTIl

  可以google一下,搜到源码vivi.tar.gz。

  前面提到的文件已经系统的分析了bootloader的,这里就按源代码来具体说事。vivi也可以分为2个阶段,阶段1的代码在arch/s3c2410/head.S中,阶段2的代码从init/main.c的main函数开始。

  阶段1

  阶段1从程序arch/s3c2410/head.S开始,按照head.S的代码执行顺序,一次完成了下面几个任务:

  关WATCH DOG (disable watch dog TImer)

  上电后,WATCH DOG默认是开着的

  禁止所有中断 (disable all interrupts)

  vivi中不会用到中断,中断是系统的事,bootloader可不能去干这事的(不过这段代码实在多余,上电后中断默认是关闭的)

  初始化系统时钟(iniTIalise system clocks)

  启动MPLL,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为“Asynchronous bus mode”。

  初始化内存控制寄存器(memsetup)

  S3c2410共有15个寄存器,在此开始初始化13个寄存器。

  检查是否从掉电模式唤醒(Check if this is a wake-up from sleep)若是,则调用WakeupStart函数进行处理。

  点亮所有LED (All LED on)

  点一下灯,通知外面的同志,告诉他们有情况发生。

  初始化UART0 (set GPIO for UART & InitUART)

  a.设置GPIO,选择UART0使用的引脚

  b.初始化UART0,设置工作方式(使用FIFO)、波特率115200 8N1、无流控等。这可是使用串口与s3c2410通信的条件啊,在终端也要如此设置。

  跳到内存测试函数(simple memory test to find some DRAM flaults)

  当然要定义了CONFIG_BOOTUP_MEMTEST这个参数才会跳到内存测试。

  如果定义了以Nand flash方式启动(#ifdef CONFIG_S3C2410_NAND_BOOT),则此时要将vivi所有代码(包括阶段1和阶段2)从Nand flash复制到SDRAM中(因为在Nand flash中是不能执行程序的,它只能做为程序和数据的存储器,而Nor flash可就不同了,Nor flash可以执行程序,但贵是它发展的瓶颈):

  a.设置nand flash控制寄存器

  b.设置堆栈指针

  c.设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单位)

  d.调用nand_read_ll进行复制

  跳到bootloader的阶段2运行,亦即调用init/main.c中的main函数(get read to call C functions)

  a.重新设置堆栈

  b.设置main函数的参数

  c.调用main函数

  head.S有900多行,都是些arm汇编,看的云山雾罩,汇编看来是忘的差不多了,所以这部分代码也看的相当糙,只知道大概在干什么,至于个中缘由就不是很了解。先学学arm汇编再回来看。

  阶段2

  从init/main.c中的main函数开始,终于步入C语言的世界了。Main函数总共有8步(8 steps),先看看源代码:

  int main(int argc, char *argv[])

  {

  int ret;

  /*

  * Step 1:

  */

  putstr("\r\n");

  putstr(vivi_banner); //vivi_banner是vivi执行开始的显示信息,vivi_banner在文件version.c中定义

  reset_handler();

  /*

  * Step 2:

  */

  ret = board_init();

  if (ret) {

  putstr("Failed a board_init() procedure\r\n");

  error();

  }

  /*

  * Step 3:

  */

  mem_map_init();

  mmu_init();

  putstr("Succeed memory mapping.\r\n");

  /*

  * Now, vivi is running on the ram. MMU is enabled.

  * Step 4:

  */

  /* initialize the heap area*/

  ret = heap_init();

  if (ret) {

  putstr("Failed initailizing heap region\r\n");

  error();

  }

  /* Step 5:

  * MTD

  */

  ret = mtd_dev_init();

  /* Step 6:

  */

  init_priv_data();

  /* Step 7:

  */

  misc();

  init_builtin_cmds();

  /* Step 8:

  */

  boot_or_vivi();

  return 0;

  }

  下面按照上面的步骤逐步来分析一下。

  1、Step 1:reset_handler()

  reset_handler用于将内存清零,代码在lib/reset_handle.c中。

  1 void

  2 reset_handler(void)

  3 {

  4 int pressed;

  5 pressed = is_pressed_pw_btn(); /*判断是硬件复位还是软件复位*/

  6 if (pressed == PWBT_PRESS_LEVEL) {

  7 DPRINTK("HARD RESET\r\n");

  8 hard_reset_handle(); /*调用clear_mem对SDRAM清0*/

  9 } else {

  10 DPRINTK("SOFT RESET\r\n");

  11 soft_reset_handle(); /*此函数为空*/

  12 }

  13 }

  在上电后,reset_handler调用第8行的hard_reset_handle(),此函数在lib/reset_handle.c中:

  [main(int argc, char *argv[]) -> reset_handler() -> hard_reset_handle()]

  1 static void

  2 hard_reset_handle(void)

  3 {

  4 #if 0

  5 clear_mem((unsigned long)(DRAM_BASE + VIVI_RAM_ABS_POS), \

  6 (unsigned long)(DRAM_SIZE - VIVI_RAM_ABS_POS));

  7 #endif

  /*lib/memory.c,将起始地址为USER_RAM_BASE,长度为USER_RAM_SIZE的内存清0*/

  8 clear_mem((unsigned long)USER_RAM_BASE, (unsigned long) USER_RAM_SIZE);

  9 }

  先写到这儿吧。

  2、Step 2:board_init()

  board_init调用2个函数用于初始化定时器和设置各GPIO引脚功能,代码在arch/s3c2410/smdk.c中:

  [main(int argc, char *argv[]) > board_init()]

  1 int board_init(void)

  2 {

  3 init_time(); /*arch/s3c2410/proc.c*/

  4 set_gpios(); /*arch/s3c2410/smdk.c */

  5 return 0;

  6 }

  init_time() 这个函数对寄存器进行了简单的 *** 作:

  void init_time(void)

  {

  TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));

  /*s3c2410 data sheet P298*/

  /*TCFG0 = 0 | 0xf00 | 0 */

  }

  

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/dianzi/2713636.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存