为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

vivi-boot loader

2011-09-18 41页 pdf 337KB 30阅读

用户头像

is_666020

暂无简介

举报
vivi-boot loader vivi boot loader的实现 参考资料: 1. 嵌入式系统 Boot Loader 技术内幕, 詹荣开 (zhanrk@sohu.com) 2. Getting started with VIVI, Janhoon Lyu, nandy@mizi.com 3. 嵌入式设备上的 Linux 系统开发,A. Santhanam etc. 4. Linux system development on an embedded device, A. Santhanam 5. vivi 有关资料 http:...
vivi-boot loader
vivi boot loader的实现 参考资料: 1. 嵌入式系统 Boot Loader 技术内幕, 詹荣开 (zhanrk@sohu.com) 2. Getting started with VIVI, Janhoon Lyu, nandy@mizi.com 3. 嵌入式设备上的 Linux 系统开发,A. Santhanam etc. 4. Linux system development on an embedded device, A. Santhanam 5. vivi 有关资料 http://www.mizi.com/developer/s3c2410x/index.html 6. smdk2410的硬件和软件/linux相关资料 http://www.samsung.com search 2410 :本文文字结构照抄” 嵌入式系统 Boot Loader 技术内幕, 詹荣开 (zhanrk@sohu.com)” 一文,以vivi中head.S作为stage1, main()作为stage2,解释了 VIVI for SMDK2410 (based on S3C2410) 开发系统的bootloader的实现。将原文放在 这里是为了方便读者。注意,VIVI的实现并非完全跟原文一致。多谢原文作者詹 大侠的详细解释。 附录有一节__SETUP在 kernel的作用来自 jeppeter (member) from http:// linuxforum.net 文中对MTD subsystem linux没作解释。Google “MTD linux subsystem 文件系统 JFSS2 ”可以获得足够的解释。 如有错误,烦请email jonesxu@gmail.com告知。多些 Ver.0.95 Jones S Z Xu jonesxu@gmail.com 2004-09-29 Chapter 1 Boot loader基本结构 由于 Boot Loader 的实现依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为 stage1 和 stage2 两大部分。依赖于 CPU 体系结构的代码,比如设备初始化代码等,通常都放在 stage1 中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而 stage2 则通常用 C语言来 实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。 Boot Loader 的 stage1 通常包括以下步骤(以执行的先后顺序): 硬件设备初始化。 为加载 Boot Loader 的 stage2 准备 RAM 空间。 拷贝 Boot Loader 的 stage2 到 RAM 空间中。 设置好堆栈。 跳转到 stage2 的 C 入口点。 Boot Loader 的 stage2 通常包括以下步骤(以执行的先后顺序): 初始化本阶段要使用到的硬件设备。 检测系统内存映射(memory map)。 将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中。 为内核设置启动参数。 调用内核。 1.1 Boot Loader 的 stage1 1.1.1 基本的硬件初始化 这是 Boot Loader 一开始就执行的操作,其目的是为 stage2 的执行以及随后的 kernel 的执行准备 好一些基本的硬件环境。它通常包括以下步骤(以执行的先后顺序): 1. 屏蔽所有的中断。为中断提供服务通常是 OS 设备驱动程序的责任,因此在 Boot Loader 的执 行全过程中可以不必响应任何中断。中断屏蔽可以通过写 CPU 的中断屏蔽寄存器或状态寄存器 (比如 ARM 的 CPSR 寄存器)来完成。 2. 设置 CPU 的速度和时钟频率。 3. RAM 初始化。包括正确地设置系统的内存控制器的功能寄存器以及各内存库控制寄存器等。 4. 初始化 LED。典型地,通过 GPIO 来驱动 LED,其目的是明系统的状态是 OK 还是 Error。 如果板子上没有 LED,那么也可以通过初始化 UART 向串口打印 Boot Loader 的 Logo 字符信息 来完成这一点。 5. 关闭 CPU 内部指令/数据 cache。 VIVI在第一阶段完成以下任务 Disable watch dog timer ; disable all interrupts ; initialise system clocks; initialise the static memory All LED on set GPIO for UART Initialize UART 0 ; copy_myself to ram; jump to ram get read to call C functions setup stack pointer call main 1.1.2 为加载 stage2 准备 RAM 空间 为了获得更快的执行速度,通常把 stage2 加载到 RAM 空间中来执行,因此必须为加载 Boot Loader 的 stage2 准备好一段可用的 RAM 空间范围。 由于 stage2 通常是 C 语言执行代码,因此在考虑空间大小时,除了 stage2 可执行映象的大小 外,还必须把堆栈空间也考虑进来。此外,空间大小最好是 memory page 大小(通常是 4KB)的倍 数。一般而言,1M 的 RAM 空间已经足够了。具体的地址范围可以任意安排,比如 blob 就将它的 stage2 可执行映像安排到从系统 RAM 起始地址 0xc0200000 开始的 1M 空间内执行。但是,将 stage2 安排到整个 RAM 空间的最顶 1MB(也即(RamEnd-1MB) - RamEnd)是一种值得推荐的方 法。 为了后面的叙述方便,这里把所安排的 RAM 空间范围的大小记为:stage2_size(字节),把起始地 址和终止地址分别记为:stage2_start 和 stage2_end(这两个地址均以 4 字节边界对齐)。因此: stage2_end=stage2_start+stage2_size 另外,还必须确保所安排的地址范围的的确确是可读写的 RAM 空间,因此,必须对你所安排的地 址范围进行测试。具体的测试可以采用类似于 blob 的方法,也即:以 memory page 为被测试 单位,测试每个 memory page 开始的两个字是否是可读写的。为了后面叙述的方便,我们记这个 检测算法为:test_mempage,其具体步骤如下: 1. 先保存 memory page 一开始两个字的内容。 2. 向这两个字中写入任意的数字。比如:向第一个字写入 0x55,第 2 个字写入 0xaa。 3. 然后,立即将这两个字的内容读回。显然,我们读到的内容应该分别是 0x55 和 0xaa。如果不 是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。 4. 再向这两个字中写入任意的数字。比如:向第一个字写入 0xaa,第 2 个字中写入 0x55。 5. 然后,立即将这两个字的内容立即读回。显然,我们读到的内容应该分别是 0xaa 和 0x55。如 果不是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。 6. 恢复这两个字的原始内容。测试完毕。 为了得到一段干净的 RAM 空间范围,我们也可以将所安排的 RAM 空间范围进行清零操作。 1.1.3 拷贝 stage2 到 RAM 中 拷贝时要确定两点:(1) stage2 的可执行映象在固态存储设备的存放起始地址和终止地址;(2) RAM 空间的起始地址。 1.1.4 设置堆栈指针 sp 堆栈指针的设置是为了执行 C 语言代码作好准备。通常我们可以把 sp 的值设置为(stage2_end- 4),也即在 1.1.2 节所安排的那个 1MB 的 RAM 空间的最顶端(堆栈向下生长)。 此外,在设置堆栈指针 sp 之前,也可以关闭 led 灯,以提示用户我们准备跳转到 stage2。 经过上述这些执行步骤后,系统的物理内存布局应该如下图 2所示。 1.1.5 跳转到 stage2 的 C 入口点 在上述一切都就绪后,就可以跳转到 Boot Loader 的 stage2 去执行了。比如,在 ARM 系统中, 这可以通过修改 PC 寄存器为合适的地址来实现。 head.S 负责完成硬件初始化操作,具体分析见源码注释 ,汇编差不多忘光了,下面注释中有关汇 编的东西多些。 其中"linkage.h" #define SYMBOL_NAME_STR(X) #X #define SYMBOL_NAME(X) X #ifdef __STDC__ #define SYMBOL_NAME_LABEL(X) X##: #else #define SYMBOL_NAME_LABEL(X) X/**/: #endif #define __ALIGN .align 0 #define __ALIGN_STR ".align 0" #ifdef __ASSEMBLY__ #define ALIGN __ALIGN #define ALIGN_STR __ALIGN_STR #define ENTRY(name) \ .globl SYMBOL_NAME(name); \ ALIGN; \ SYMBOL_NAME_LABEL(name) #endif 其中"machine.h" 包括了 smdk2410.h (有关开发板的配置) , 包括memory map, Porocessor memory map ,FLASH, ROM, DRAM的物理地址和在 VIVI中用 的虚拟地址(?),Architecture magic and machine type, UART,CPU,DRAM的初始化参数等 smdk2410.h进一步包括 s3c2410.h, 有关 CPU的设置,Definition of constants related to the S3C2410 microprocessor(based on ARM 920T). /* * vivi/arch/s3c2410/head.S: * Initialise hardware * * Copyright (C) 2001 MIZI Research, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * Author: Janghoon Lyu * Date : $Date: 2003/02/26 10:38:11 $ * * $Revision: 1.18 $ * * * History: * * 2002-05-14: Janghoon Lyu * - Initial code * */ #include "config.h" //Æautoconf.h 空的 #include "linkage.h" //定义 #include "machine.h" @ Start of executable code ENTRY(_start) //入口点 ENTRY(ResetEntryPoint) @ @ Exception vector table (physical address = 0x00000000) @ //异常向量 表 物理地址 0x0000000 @ 0x00: Reset //最 基本操作 :复位 B 是最简单的分支。一旦遇到一个 B 指令,ARM 处 理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的 R15 的 b Reset @ 0x04: Undefined instruction exception //处理未定义的指令 UndefEntryPoint: b HandleUndef @ 0x08: Software interrupt exception //软中断 SWIEntryPoint: b HandleSWI @ 0x0c: Prefetch Abort (Instruction Fetch Memory Abort) //中文名不知道 PrefetchAbortEnteryPoint: b HandlePrefetchAbort @ 0x10: Data Access Memory Abort // DataAbortEntryPoint: b HandleDataAbort @ 0x14: Not used //空 NotUsedEntryPoint: b HandleNotUsed @ 0x18: IRQ(Interrupt Request) exception //中断(普通) IRQEntryPoint: b HandleIRQ @ 0x1c: FIQ(Fast Interrupt Request) exception // fast 中断处理 FIQEntryPoint: b HandleFIQ @ @ VIVI magics @ @ 0x20: magic number so we can verify that we only put .long 0 @ 0x24: .long 0 @ 0x28: where this vivi was linked, so we can put it in memory in the right place .long _start @ 0x2C: this contains the platform, cpu and machine id .long ARCHITECTURE_MAGIC @ 0x30: vivi capabilities .long 0 #ifdef CONFIG_PM // power management //vivi未用 @ 0x34: b SleepRamProc #endif #ifdef CONFIG_TEST //test mode vivi未用 @ 0x38: b hmi #endif @ @ Start VIVI head @ Reset: //第一步 RESET @ disable watch dog timer //disable watch dog定时器 mov r1, #0x53000000 mov r2, #0x0 str r2, [r1] //add 0x5300_0000 清 0,bit 5=0 disable this timer #ifdef CONFIG_S3C2410_MPORT3 //另一种 Platform 非 SMDK mov r1, #0x56000000 mov r2, #0x00000005 str r2, [r1, #0x70] mov r2, #0x00000001 str r2, [r1, #0x78] mov r2, #0x00000001 str r2, [r1, #0x74] #endif @ disable all interrupts //禁止 所有中断 mov r1, #INT_CTL_BASE //0x4A00_0000 source pending register mov r2, #0xffffffff str r2, [r1, #oINTMSK] //0x4A00_0008 //0x4A00_0008 INTERRUPT MASK register=0xFFFFFFFF, disable all int ldr r2, =0x7ff str r2, [r1, #oINTSUBMSK] //0x4A00_001C //Interrupt sub mask register , bit[10:0] = 1 ->0x7FF ->disable all @ initialise system clocks //初始化系统时钟 mov r1, #CLK_CTL_BASE // LOCK TIME COUNT REGISTER(LOCKTIME) //0x4c000000 mvn r2, #0xff000000 str r2, [r1, #oLOCKTIME] //0x4C000000 ->0xFF00_0000; @ldr r2, mpll_50mhz //CPU定成 50Mhz @str r2, [r1, #oMPLLCON] // #ifndef CONFIG_S3C2410_MPORT1 //如果未定义成 MPORT1 (一种 plat form) @ 1:2:4 mov r1, #CLK_CTL_BASE mov r2, #0x3 str r2, [r1, #oCLKDIVN] // // vCLKDIVN 0x3 /* FCLK:HCLK:PCLK = 1:2:4 */ mrc p15, 0, r1, c1, c0, 0 @ read ctrl register orr r1, r1, #0xc0000000 @ Asynchronous mcr p15, 0, r1, c1, c0, 0 @ write ctrl register @ now, CPU clock is 200 Mhz //CPU定成 200Mhz mov r1, #CLK_CTL_BASE ldr r2, mpll_200mhz str r2, [r1, #oMPLLCON] #else //platform= MPORT1 ,以下不理 @ 1:2:2 mov r1, #CLK_CTL_BASE ldr r2, clock_clkdivn str r2, [r1, #oCLKDIVN] mrc p15, 0, r1, c1, c0, 0 @ read ctrl register orr r1, r1, #0xc0000000 @ Asynchronous mcr p15, 0, r1, c1, c0, 0 @ write ctrl register @ now, CPU clock is 100 Mhz mov r1, #CLK_CTL_BASE ldr r2, mpll_100mhz str r2, [r1, #oMPLLCON] #endif bl memsetup //第 2步memsetup #ifdef CONFIG_PM //如果有 Power management:不用 @ Check if this is a wake-up from sleep ldr r1, PMST_ADDR ldr r0, [r1] tst r0, #(PMST_SMR) bne WakeupStart #endif #ifdef CONFIG_S3C2410_SMDK //SMDK platform @ All LED on //点灯,好歹通知一下外面的同志 3 mov r1, #GPIO_CTL_BASE add r1, r1, #oGPIO_F ldr r2,=0x55aa str r2, [r1, #oGPIO_CON] mov r2, #0xff str r2, [r1, #oGPIO_UP] mov r2, #0x00 str r2, [r1, #oGPIO_DAT] #endif #if 0 @ SVC mrs r0, cpsr bic r0, r0, #0xdf orr r1, r0, #0xd3 msr cpsr_all, r1 #endif //设置串口 ,内外联络的通道 @ set GPIO for UART mov r1, #GPIO_CTL_BASE // 0x5600_0000 add r1, r1, #oGPIO_H // oGPIO_H 0x70 PORT H CONTROL REGISTERS ldr r2, gpio_con_uart // vGPHCON= 0x0016faaa str r2, [r1, #oGPIO_CON] // 01 01 10 11 11 10 10 10 10 10 10 B //oGPIO_CON = 0x0 // GPH0 bit[1:0] = 10 nCTS0 // GPH1 bit[3:2] = 10 nRTS0 // GPH2 bit[5:4] = 10 TXD0 // GPH3 bit[7:6] = 10 RXD0 // GPH4 bit[9:8] = 10 TXD1 // GPH5 bit[11:10] = 10 RXD1 // GPH6 bit[13:12] = 11 nRTS1 // GPH7 bit[15:14] = 11 nCTS1 // GPH8 bit[17:16] = 10 UEXTCLK // GPH9 bit[19:18] = 01 Output // GPH10 bit[21:20] = 01 Output ldr r2, gpio_up_uart // vGPHUP 0x000007ff = 0111 1111 1111 B str r2, [r1, #oGPIO_UP] // oGPIO_UP 0x8 /* R/W, Pull-up disable register */ // 0x7FF -> 1: The pull-up function is disabled. For all GPHx // reg GPHUP 0x56000078 bl InitUART //initialize UART #ifdef CONFIG_DEBUG_LL //low level debugging info @ Print current Program Counter //vivi def没用 ldr r1, SerBase //往串口上输出 info mov r0, #'\r' bl PrintChar mov r0, #'\n' bl PrintChar mov r0, #'@' bl PrintChar mov r0, pc bl PrintHexWord #endif #ifdef CONFIG_BOOTUP_MEMTEST // comment 'Low Level Hardware Debugging' bool ' Enable simple memory test' CONFIG_BOOTUP_MEMTEST //vivi def没用 @ simple memory test to find some DRAM flaults. bl memtest //check the first 1MB in increments of 4k//改大点 3 #endif #ifdef CONFIG_S3C2410_NAND_BOOT bl copy_myself @ jump to ram ldr r1, =on_the_ram //将 on_the_ram的地址装入 r1 add pc, r1, #0 //pc = r1+0 nop nop 1: b 1b @ infinite loop //硬是看不懂这个 B on_the_ram: #endif #ifdef CONFIG_DEBUG_LL ldr r1, SerBase ldr r0, STR_STACK bl PrintWord ldr r0, DW_STACK_START bl PrintHexWord #endif @ get read to call C functions ldr sp, DW_STACK_START @ setup stack pointer // STACK_BASE+STACK_SIZE-4 // STACK_BASE = (VIVI_PRIV_RAM_BASE - STACK_SIZE) //STACK从上往下用。 所以 STACK_START = STACK_BASE+STACK_SIZE-4 mov fp, #0 @ no previous frame, so fp=0 mov a2, #0 @ set argv to NULL bl main @ call main //如果正常,一去不复返的了 mov pc, #FLASH_BASE @ otherwise, reboot, //FLASH_BASE=ROM_BASE0 = 0x0 @ @ End VIVI head @ /* * subroutines */ @ @ Wake-up codes @ #ifdef CONFIG_PM WakeupStart: // power management 用 @ Clear sleep reset bit ldr r0, PMST_ADDR mov r1, #PMST_SMR str r1, [r0] @ Release the SDRAM signal protections ldr r0, PMCTL1_ADDR ldr r1, [r0] bic r1, r1, #(SCLKE | SCLK1 | SCLK0) str r1, [r0] @ Go... ldr r0, PMSR0_ADDR @ read a return address ldr r1, [r0] mov pc, r1 nop nop 1: b 1b @ infinite loop SleepRamProc: //power management用 @ SDRAM is in the self-refresh mode */ ldr r0, REFR_ADDR ldr r1, [r0] orr r1, r1, #SELF_REFRESH str r1, [r0] @ wait until SDRAM into self-refresh mov r1, #16 1: subs r1, r1, #1 bne 1b @ Set the SDRAM singal protections ldr r0, PMCTL1_ADDR ldr r1, [r0] orr r1, r1, #(SCLKE | SCLK1 | SCLK0) str r1, [r0] /* Sleep... Now */ ldr r0, PMCTL0_ADDR ldr r1, [r0] orr r1, r1, #SLEEP_ON str r1, [r0] 1: b 1b #ifdef CONFIG_TEST hmi: ldr r0, PMCTL0_ADDR // PMCTL0_ADDR: .long 0x4c00000c, Clock Gen Ctrl ldr r1, =0x7fff0 // reset clock gen ctrl str r1, [r0] @ All LED on //点灯? mov r1, #GPIO_CTL_BASE add r1, r1, #oGPIO_F ldr r2,=0x55aa str r2, [r1, #oGPIO_CON] mov r2, #0xff str r2, [r1, #oGPIO_UP] mov r2, #0xe0 str r2, [r1, #oGPIO_DAT] 1: b 1b #endif #endif ENTRY(memsetup) //memsetup子程序 @ initialise the static memory @ set memory control registers mov r1, #MEM_CTL_BASE //memory controller adrl r2, mem_cfg_val add r3, r1, #52 1: ldr r4, [r2], #4 str r4, [r1], #4 cmp r1, r3 bne 1b mov pc, lr //这里返回了么? 注意注意:这里memsetup已经返回了,下面是独立的子程序了呢 #ifdef CONFIG_S3C2410_NAND_BOOT // NAND如此,NOR应该如何处理呢? @ //不需要 copy vivi to ram????? @ copy_myself: copy vivi to ram @ copy_myself: mov r10, lr @ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =0xf830 @ initial value str r2, [r1, #oNFCONF] ldr r2, [r1, #oNFCONF] bic r2, r2, #0x800 @ enable chip str r2, [r1, #oNFCONF] mov r2, #0xff @ RESET command strb r2, [r1, #oNFCMD] mov r3, #0 @ wait 1: add r3, r3, #0x1 cmp r3, #0xa blt 1b 2: ldr r2, [r1, #oNFSTAT] @ wait ready tst r2, #0x1 beq 2b ldr r2, [r1, #oNFCONF] orr r2, r2, #0x800 @ disable chip str r2, [r1, #oNFCONF] @ get read to call C functions (for nand_read()) ldr sp, DW_STACK_START @ setup stack pointer mov fp, #0 @ no previous frame, so fp=0 @ copy vivi to RAM ldr r0, =VIVI_RAM_BASE //(DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE) //0x33f00000 mov r1, #0x0 //start address, now vivi is in steppingstone mov r2, #0x20000 //128k ? bl nand_read_ll // nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) // ro = buf , r1 =start , size = r2=128k ??yeah ? 要这么多干吗? tst r0, #0x0 //返回值在 r0中 beq ok_nand_read //nand_read_ll()顺利返回 #ifdef CONFIG_DEBUG_LL bad_nand_read: ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord 1: b 1b @ infinite loop #endif ok_nand_read: #ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif @ verify mov r0, #0 //flash start add? no. 是用 NAND启动时,从 NAND copy 到 phy add=0的 4Kbytes SRAM(stepping stone)中的 vivi ldr r1, =0x33f00000 //VIVI_RAM_BASE // VIVI_RAM_BASE = (DRAM_BASE + DRAM_SIZE(64M) - VIVI_RAM_SIZE) //= 0x3000_0000+0x0400_0000-0x0010_0000 = 0x33f0_0000 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes //移 4K去 VIVI_RAM_BASE ?NO 比较 4Kbytes? YES go_next: ldr r3, [r0], #4 //将[r0]指向的数据(32bit?)放进 r3 ,然后 r0+4->r0 ldr r4, [r1], #4 //将[r1]指向的数据(32bit?)放进 r4 ,然后 r1+4->r1 teq r3, r4 //比较 r3/r4的大小 bne notmatch //出现不匹配的情况 subs r2, r2, #4 //r2-4 ->r2, if subs 结果为 0,flagZ==1 beq done_nand_read //若 r2==0条件(flagZ==1)成立,跳到 done_nand_read bne go_next //flagZ==0; 说明 r2!=0 notmatch: #ifdef CONFIG_DEBUG_LL sub r0, r0, #4 ldr r1, SerBase bl PrintHexWord ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord #endif 1: b 1b //匹配与否,不匹配时去哪里了? done_nand_read: #ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif mov pc, r10 //返回罗,在函数入口处mov r10, lr @ clear memory @ r0: start address @ r1: length mem_clear: mov r2, #0 mov r3, r2 mov r4, r2 mov r5, r2 mov r6, r2 mov r7, r2 mov r8, r2 mov r9, r2 clear_loop: stmia r0!, {r2-r9} subs r1, r1, #(8 * 4) bne clear_loop mov pc, lr #endif @ CONFIG_S3C2410_NAND_BOOT #ifdef CONFIG_BOOTUP_MEMTEST // Low Level Hardware DebuggingÆ Enable simple memory test //vivi未用 @ @ Simple memory test function @ memtest: mov r10, lr #ifdef CONFIG_DEBUG_LL //low level debugging,往 serport上面捣腾信息 mov r0, #'M' ldr r1, SerBase bl PrintChar mov r0, #'T' ldr r1, SerBase bl PrintChar mov r0, #'S' ldr r1, SerBase bl PrintChar mov r0, #'T' ldr r1, SerBase bl PrintChar mov r0, #' ' ldr r1, SerBase bl PrintChar #endif /* check the first 1MB in increments of 4k */ //循环测试 1M得 SDRAM//我们应该改大 点 mov r7, #0x1000 mov r6, r7, lsl #8 /* 4k << 2^8 = 1MB */ mov r5, #DRAM_BASE //DRAM_BASE =DRAM_BASE0= 0x30000000 /* base address of dram bank 0 */ mem_test_loop: mov r0, r5 bl testram_nostack teq r0, #1 beq badram add r5, r5, r7 subs r6, r6, r7 bne mem_test_loop @ the first megabyte is OK. so let us clear it. mov r0, #((1024 * 1024) / (8 * 4)) @ 1MB in steps of 32 bytes mov r1, #DRAM_BASE mov r2, #0 mov r3, #0 mov r4, #0 mov r5, #0 mov r6, #0 mov r7, #0 mov r8, #0 mov r9, #0 clear_loop_memtest: stmia r1!, {r2-r9} subs r0, r0, #(8 * 4) bne clear_loop_memtest #ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif mov pc, r10 @ return memtest return badram: #ifdef CONFIG_DEBUG_LL ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord #endif 1: b 1b @ loop 有坏// 死循环? @ testmem.S: memory tester, test if there is RAM available at given location @ //called by memtest @ Copyright (C) 2001 Russell King (rmk@arm.linux.org.uk) @ @ This version clobbers registers r1-r4, so be sure to store their contents @ in a safe position. This function is not APCS compliant, so only use it @ from assembly code. @ @ r0 = address to test @ returns r0 = 0 - ram present, r0 = 1 - no ram @ clobbers r1 - r4 ENTRY(testram_nostack) ldmia r0, {r1, r2} @ store current value in r1 and r2 mov r3, #0x55 @ write 0x55 to first word mov r4, #0xaa @ 0xaa to second stmia r0, {r3, r4} ldmia r0, {r3, r4} @ read it back teq r3, #0x55 @ do the values match teqeq r4, #0xaa bne bad @ oops, no mov r3, #0xaa @ write 0xaa to first word mov r4, #0x55 @ 0x55 to second stmia r0, {r3, r4} ldmia r0, {r3, r4} @ read it back teq r3, #0xaa @ do the values match teqeq r4, #0x55 bad: stmia r0, {r1, r2} @ in any case, restore old data moveq r0, #0 @ ok - all values matched movne r0, #1 @ no ram at this location mov pc, lr #endif @ CONFIG_BOOTUP_MEMTEST @ Initialize UART @ @ r0 = number of UART port //SerBase = UART0_CTL_BASE = UART_CTL_BASE =0x50000000 // 0x5000_0000 UART channel 0 line control register InitUART: ldr r1, SerBase //0x5000_0000 mov r2, #0x0 str r2, [r1, #oUFCON] //清零 oUFCON //#define oUFCON 0x08 /* R/W, UART FIFO control register */ // UFCON0 0x50000008 R/W UART channel 0 FIFO control register Tx FIFO Trigger Level [7:6] : 00 : Empty Rx FIFO Trigger Level [5:4]: 00 : 00 = 4-byte Tx FIFO Reset [2] : 0 = Normal Rx FIFO Reset [1] : 0 = Normal FIFO Enable [0
/
本文档为【vivi-boot loader】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索