移植嵌入式Linux到ARM处理器S3C2410:BootLoader
2012-10-04
宋宝华
标签: Linux S3C2410

4. BootLoader第二阶段

vivi Bootloader的第二阶段又分成了八个小阶段,在main函数中分别调用这几个小阶段的相关函数:

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

{

int ret;

/*

* Step 1:

*/

putstr("\r\n");

putstr(vivi_banner);

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:

*/

ret = mtd_dev_init();

/* Step 6:

*/

init_priv_data();

/* Step 7:

*/

misc();

init_builtin_cmds();

/* Step 8:

*/

boot_or_vivi();

return 0;

}

STEP1的putstr(vivi_banner)语句在串口输出一段字符说明vivi的版本、作者等信息,vivi_banner定义为:

const char *vivi_banner =

"VIVI version " VIVI_RELEASE " (" VIVI_COMPILE_BY "@"

VIVI_COMPILE_HOST ") (" VIVI_COMPILER ") " UTS_VERSION "\r\n";

reset_handler进行相应的复位处理:

void

reset_handler(void)

{

int pressed;

pressed = is_pressed_pw_btn();

if (pressed == PWBT_PRESS_LEVEL) {

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

hard_reset_handle();

} else {

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

soft_reset_handle();

}

}

hard_reset_handle会clear内存,而软件复位处理则什么都不做:

static void

hard_reset_handle(void)

{

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

}

STEP2进行板初始化,设置时间和可编程I/O口:

int board_init(void)

{

init_time();

set_gpios();

return 0;

}

STEP3进行内存映射及MMU初始化:

void mem_map_init(void)

{

#ifdef CONFIG_S3C2410_NAND_BOOT

mem_map_nand_boot();

#else

mem_map_nor();

#endif

cache_clean_invalidate();

tlb_invalidate();

}

S3C2410A的MMU初始化只需要调用通用的arm920 MMU初始化函数:

static inline void arm920_setup(void)

{

unsigned long ttb = MMU_TABLE_BASE;

__asm__(

/* Invalidate caches */

"mov r0, #0\n"

"mcr p15, 0, r0, c7, c7, 0\n" /* invalidate I,D caches on v4 */

"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */

"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate I,D TLBs on v4 */

/* Load page table pointer */

"mov r4, %0\n"

"mcr p15, 0, r4, c2, c0, 0\n" /* load page table pointer */

/* Write domain id (cp15_r3) */

"mvn r0, #0\n" /* Domains 0, 1 = client */

"mcr p15, 0, r0, c3, c0, 0\n" /* load domain access register */

/* Set control register v4 */

"mrc p15, 0, r0, c1, c0, 0\n" /* get control register v4 */

/* Clear out 'unwanted' bits (then put them in if we need them) */

/* .RVI ..RS B... .CAM */

"bic r0, r0, #0x3000\n" /* ..11 .... .... .... */

"bic r0, r0, #0x0300\n" /* .... ..11 .... .... */

"bic r0, r0, #0x0087\n" /* .... .... 1... .111 */

/* Turn on what we want */

/* Fault checking enabled */

"orr r0, r0, #0x0002\n" /* .... .... .... ..1. */

#ifdef CONFIG_CPU_D_CACHE_ON

"orr r0, r0, #0x0004\n" /* .... .... .... .1.. */

#endif

#ifdef CONFIG_CPU_I_CACHE_ON

"orr r0, r0, #0x1000\n" /* ...1 .... .... .... */

#endif

/* MMU enabled */

"orr r0, r0, #0x0001\n" /* .... .... .... ...1 */

"mcr p15, 0, r0, c1, c0, 0\n" /* write control register */

: /* no outputs */

: "r" (ttb) );

}

STEP4设置堆栈;STEP5进行mtd设备的初始化,记录MTD分区信息;STEP6设置私有数据;STEP7初始化内建命令。

STEP8启动一个SHELL,等待用户输出命令并进行相应处理。在SHELL退出的情况下,启动操作系统:

#define DEFAULT_BOOT_DELAY 0x30000000

void boot_or_vivi(void)

{

char c;

int ret;

ulong boot_delay;

boot_delay = get_param_value("boot_delay", &ret);

if (ret) boot_delay = DEFAULT_BOOT_DELAY;

/* If a value of boot_delay is zero,

* unconditionally call vivi shell */

if (boot_delay == 0) vivi_shell();

/*

* wait for a keystroke (or a button press if you want.)

*/

printk("Press Return to start the LINUX now, any other key for vivi\n");

c = awaitkey(boot_delay, NULL);

if (((c != '\r') && (c != '\n') && (c != '\0'))) {

printk("type \"help\" for help.\n");

vivi_shell();

}

run_autoboot();

return;

}

SHELL中读取用户从串口输出的命令字符串,执行该命令:

void

vivi_shell(void)

{

#ifdef CONFIG_SERIAL_TERM

serial_term();

#else

#error there is no terminal.

#endif

}

void serial_term(void)

{

char cmd_buf[MAX_CMDBUF_SIZE];

for (;;) {

printk("%s> ", prompt);

getcmd(cmd_buf, MAX_CMDBUF_SIZE);

/* execute a user command */

if (cmd_buf[0])

exec_string(cmd_buf);

}

}

5.电路板调试

在电路板的调试过程中,我们首先要在ADT新建的工程中添加第一阶段的汇编代码head.S文件,修改Link脚本,将代码和数据映射到S3C2410A自带的0x40000000开始的4KB内存空间内:

SECTIONS

{

. = 0x40000000;

.text : { *(.text) }

Image_RO_Limit = .;

Image_RW_Base = .;

.data : { *(.data) }

.rodata : { *(.rodata) }

Image_ZI_Base = .;

.bss : { *(.bss) }

Image_ZI_Limit = .;

__bss_start__ = .;

__bss_end__ = .;

__EH_FRAME_BEGIN__ = .;

__EH_FRAME_END__ = .;

PROVIDE (__stack = .);

end = .;

_end = .;

.debug_info 0 : { *(.debug_info) }

.debug_line 0 : { *(.debug_line) }

.debug_abbrev 0 : { *(.debug_abbrev)}

.debug_frame 0 : { *(.debug_frame) }

}

借助万用表、示波器等仪器仪表,调通SDRAM,并将vivi中自带的串口、NAND FLASH驱动添加到工程中,调试通过板上的串口和FLASH。如果板电路的原理与三星公司DEMO板有差距,则vivi中硬件的操作要进行相应的修改。全部调试通过后,修改vivi源代码,重新编译vivi,将其烧录入NAND FLASH就可以在复位后启动这个Bootloader了。

调试板上的新增硬件时,宜在ADT中添加相应的代码,在不加载操作系统的情况下,单纯地操作这些硬件。如果电路板设计有误,要进行飞线和割线等处理。

6.小结

本章讲解了ARM汇编、Bootloader的功能,Bootloader的调试环境及ARM电路板的调试方法。

共 4 页   上一页1234
可能会用到的工具/仪表
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号