bootloader开发阶段总结以及可能会碰到的问题

2023-05-16

到今天,vivi源代码基本分析完毕。对bootloader有了更深层的认识。在此期间,仔细阅读了毛德操、胡希明先生编著的《嵌入式系统--采用公开源代码和StrongARM/XScale处理器》第七章:嵌入式系统的引导和装入。看了看出版时间,才明白牛人詹荣开或许也受惠于此书。他在IBM Development上发表的那篇《嵌入式bootloader技术内幕》一文,后来在sourceforge上的开源项目jtager,在此书中有详尽的描述。(当然,他们可能是独立研究的。)两者结合起来看,对自己的帮助非常大。

 
    现在看来,bootloader主要的工作量有三个: 一是根据开发板,确定硬件初始化部分二是内存初始化,不过内存检测技术相对比较成熟了;三是 读写存储介质,包括nor/nand flash或者其他。设置内核传递参数相对前面还是比较简单的。如果完成这些基本功能,一个比较简单的实现就是blob;vivi虽然也比较小,但是还是比blob大一些,也复杂一些。有了这个基本的框架,如果公司是为了推销自己的SoC,那么会做Demo板,也就是所谓的“公版”,为之开发bootloader,并不打算支持更多的SoC,比如blob,vivi都是这样。他们的功能并不完善, 如果后来的维护者想要增强功能,一是在下载手段上下功夫,比如增加tftp下载或者usb下载,二是在支持文件系统方面做工作。另外有机构专门开发并维护bootloader,想要支持尽可能多的SoC,比如uboot, 它就可以在软件架构方面更多的考虑可扩展性,可移植性,同时增强上述手段,另外, 可以增加monitor功能,在内核尚未移植完成的阶段增加调试手段
 
    由此形成了对bootloader比较全面的认识。要想继续深入bootloader,那么有下面的工作:
 
    ·提高阅读datasheet,提取有用信息的能力。能够更快的开发出硬件初始化代码。
    ·掌握内存检测算法,能够快速编写。
    ·学习MTD技术,开发存储介质驱动程序。
    ·掌握tag内核参数传递技术。
 
    这些都是具体的细节的工作。在软件架构的学习上,我想还是应该以uboot为主,因为它的可移植性、可扩展性等,都是其他的bootloader不能相比的。要想在基本的简单的bootloader的基础上有所提高,那么就需要深入的去了解学习uboot。在后续的开发中,如果需要自己开发bootloader,那么就以vivi/blob为模型,重新编写;如果仅仅需要移植,而且该SoC并没有自己的bootloader,那么最好还是以uboot最为移植。
 
    bootloader算是比较简单,下点功夫完全掌握并非难事。在bootloader的学习过程中,把相关的基础继续加强巩固。我想,到07年末,这个任务应该可以完成。这次可是充分估计的学习内容的广度和深度了。要想学好,就要学深学透。这部分内容的开发也比较适合自己的知识背景。完成此部分后,再进入内核开发的驱动部分,从外围入手,逐步的深入的学习内核。课题也分配下来了,还需要在应用上做工作。要做的事情很多,但是不要急,慢慢来。还是那句话,这些技术都是非常成熟了,有文档和资料。只要静下心来,就一定能够掌握。所以,学习这些实用技术的同时,还不能忽略专业理论知识的学习。两者结合,才能走得更远。
网友: piaoxiang 时间:2007-07-28 08:14:44 IP地址:122.4.41.★
 
 
 

2007-07-28
    通过后面的vivi学习才发现,为什么会需要LINUX_INCLUDE_DIR这个宏来包含内核的头文件。很简单,vivi就是Linux kernel的小“儿女”,里面有些C文件的使用仍然用了“<>”包含的方式。而mizi公司没有经过仔细的验证分析,认为加上这个宏就不会出现编译问题。于是,为什么网上有的人把该宏定义为编译器的include目录,有些人把它定义为kernel的include目录,编译都没有问题,就不难理解了。如果你把该宏去掉编译,仍然没有问题(也许我测试的不到位)。但是我考虑的是,vivi是bootloader,应该具有引导不同版本内核的能力,所以还是要通过测试把该宏相关的内容去除比较合适。我在后续工作中已经去掉了该宏,暂时还没有发现编译问题。
    另外,增加的蜂鸣器关闭的汇编程序也不太合适。关于它的处理应该是由[init/main.c]------[arch/s3c2410/smdk.c] board_init()-----set_gpios()来完成的。也就是说vGPBCON的值不合适。应该修改[include/platform/smdk2410.h]默认的#define vGPBCON            0x00044555。这需要查看Datasheet,了解一下GPBCON各个位的含义,然后根据自己的开发板进行修改。其他的初始状态不合适,也要考虑修改此头文件中的初始值。
    需要注意的一个小地方是,在vivi的头文件中,如果寄存器前加字母v,表示value,即取值。如果加个o,则表示offset,即偏移值。这样读程序就很容易理解了。
    vivi也就逐步清晰起来了。
 
   

   
网友: spring11 时间:2007-08-31 23:40:06 IP地址:59.78.25.★
 
 
 

写得太好了,这是我看到的最详细的一篇!!
好想转到我的百度博客上,HOHO,不过这么好的文章还是每次都到里来吧:)

Blog作者的回复:
谢谢

 
   

   
网友: 本站网友 时间:2007-11-11 01:28:09 IP地址:210.72.218.★
 
 
 

佩服Super的学习态度和深度,也让我看到自己的很多不足,如果能和你成为同事,真是件辛事:)希望在以后的日子能和你多多交流,重要的是向你学习,我会给你发邮件的:)请多关照哦  

Blog作者的回复:
^_^

 
   

   
网友: bob_zhang2004 时间:2007-11-12 23:28:48 IP地址:211.103.74.★
 
 
 

太好了, 我们也正在讨论中,正在拜读你的文章, 

也 欢迎到我们的帖子,大家一起再讨论一下:

http://www.linuxforum.net/forum/showflat.php?Cat=&Board=driver&Number=664503&page=0&view=&sb=&o=&fpart=1&vc=1  

Blog作者的回复:
共同讨论。

 
   

   
网友: bob_zhang2004 时间:2007-11-13 10:52:18 IP地址:58.211.114.★
 
 
 

>> 3、主时钟源来自外部晶振或者外部时钟。复位后,MPLL虽然默认启动,但是如果不向MPLLCON中写入value,那么外部晶振直接作为系统时钟。
>> EDUKIT-III的外部晶振有两个,一是用于系统时钟,为12MHz;一个用于RTC,为32.768KHz。
>> 以前实验没有向MPLLCON写入数值,所以系统时钟都是12MHz。

>> 从这里也可以发现一个问题,如果外部晶振开始没有焊上,那么系统是无法正常启动的。因为按照上述规则,
>> 复位后还没有写入MPLLCON,这时又没有可以使用的时钟源,所以不会启动。也就是硬件完成后,这个12MHz的晶振是一定要焊上的,
>> 才能进行后续的硬件测试工作。

您这里所说的外部时钟 , 是指什么呢? 能否举个现实中的例子。 

1》不是一般情况下, 有外部晶振就够了呢? 
2》  >> 但是如果不向MPLLCON中写入value,那么外部晶振直接作为系统时钟
我的疑问是: 那我要是往 MPLLCON写入value 呢? 那谁会作为系统时钟呢?      这个时候 12MHz还有意义吗?

Blog作者的回复:
我想,你对硬件可能不是很熟悉。
1、首先,硬件系统需要一个时钟信号。我们常用石英晶振作为这个时钟信号源。你可以看看你的板子,应该有个银白色帽子的东西,那就是晶振。再深入了解,你需要看看晶振的物理原理,了解为什么能够产生时钟信号了。
2、为了产生高频,在硬件上一般采用锁相环电路,这也是高频电路的知识。简单的说,12MHz如果作为一级时钟源,只能产生12MHz的主频,要想提到200MHz,那就需要倍频。就是相当于12×n=200.锁相环电路完成这个n的作用,这就是MPLL的作用。等到得到了200MHz的时钟源,那么现在的系统时钟就是1/(200MHz)了。
3、因为硬件设计的特点,具体电路就比较复杂了。简单说,要想使MPLL真正起作用,就需要一个触发事件,而这个事件就是要往MPLLCON中写入value,确定分频比,这样电路才能接通。(主要是硬件设计部分,电路的细节我也不是太清晰,但是这种设计在51单片机等上面是很广泛的。)也就是说,你没有理解硬件上的设计,12MHz是最初的时钟源啊,即使经过了倍频,那200MHz是二级的时钟源,这个时钟体系也是一个树状的体系结构,简称时钟树。如果把12MHz去掉,那么200MHz的源是不可能得到的。
4、刚才说的是12MHz的晶振,另外还有一个32.768KHz的晶振,他们都是晶振,只不过频率不同,用途也不同。32.768KHz用于RTC,仅仅用作这个目的。它的这部分电路和12MHz的主频电路是不同的。
5、这里的术语可能不太严谨,所以产生了问题。外部晶振对应的是频率f,f=12MHz的话,那么对应的时钟就是1/f。二者在说法上是等同的。

简单总结一下,外部晶振和外部时钟实际是一个东西,说法不太严谨就是了,都是提供时钟树的硬件组件。关于高频的时钟设计上,要用分级的观点来考虑。一级时钟源一般是物理的晶振,直接产生,二级时钟源则是通过锁相环电路转换产生。很显然,少了一级物理晶振,也就不可能产生二级高频时钟了。一般是二级设计,如果是多级,就会出现时钟同步等等比较复杂的问题了。

 
   

   
网友: bob_zhang2004 时间:2007-11-14 07:23:34 IP地址:211.103.74.★
 
 
 

非常感谢你的回答, 我对硬件懂得不多, datasheet还能看懂 , 现在就是想再深入了解一下硬件原理, 这样对kernel和driver很有好处。 

听了你的阐述, 我明白了。我最后的理解是这样的: Mpll只是一个倍频输出电路, 通过它 可以 12MHz的一级时钟输入倍频输出 ,产生二级时钟,供其他的外设来使用而已。 
而 MPLLCON 寄存器的作用仅仅是提供倍频参数, 用户必须写入(在我们的环境中是 u-boot初始化的时候,写入 0x5c040) ,这样MPLL 倍频电路才能生效, 产生 200MHz的输出。 

如果用户不写入 MPLLCON 寄存器(即使有默认值),MPLL根本就不生效, 也就没有二级时钟了, 相当于 所有的外设都得 使用 12MHz的频率了。 

所以这样看起来 , 12MHz的外部晶振必须焊接上, 按您所说 ,如果没焊上 , 板子连唯一的一级时钟都没有了, 自然无法启动了。 

++++++++++++++++++++++++++++++++++++++++++++++++

Blog作者的回复:
对,就是这个意思。

 
   

   
网友: bob_zhang2004 时间:2007-11-14 07:31:17 IP地址:211.103.74.★
 
 
 

对于 PLL VALUE SELECTION TABLE 表我还是有点疑惑:望指教:
图请看这里 http://blogimg.chinaunix.net/blog/upfile2/071112215834.jpg

1>  MDIV和 HDIV ,SDIV 默认值分别是 : 0x5c , 0x4 , 0x00 
但是为什么表里没有0x5c 呢? 倒是有0x52 , 
PDIV 和 SDIV , 也没有对应的 0x04 和 0x0 啊? 


Blog作者的回复:
看看公式:Mpll(Fclk)=(m×Fin)/(p×(2^s))【m=MDIV+8, p=PDIV+2,s=SDIV】
这里面有两个需要注意。一个是Fin,就是说这是一级时钟源的频率,F代表Frequency,in代表input。Mpll实际上是Main锁相环电路的本地输出频率,实际上就是系统的Fclk。现在已知Fin为12MHz,要想获得Mpll,取决于三个参数。但是这三个参数可以是任意的,并没有死规定,也就是我前面说的,这是一个多解方程式。
手册上也说过,表中的数据是可靠的,应用没有问题。如果我想要得到200MHz,但是表中并没有这个输出频率,而官方提供的vivi中使用了这个200MHz,说明这个数据也是可靠的。所以在s3c2410中就普遍的使用可以生成200MHz的这三个参数了。可以说,这三个参数是源于vivi的。之所以选择200MHz,也是为了精确定时。比如sdram的刷新频率的选择,等等。
总之,datasheet给定了公式和table。table只是官方经过测试比较稳定的一些参数组合,并非全部。还可以有任意多的组合方式,但是呢,官方不保证你自己选择的参数在硬件上稳定可靠。而vivi也是官方的,它提供了datasheet上没有的200MHz输出的一组参数,所以在200MHz这个时钟频率上就普遍的采用了0x5c 0x4 0x00。因为选择200MHz在很多与时间相关的设置上的方便性,就使得200MHz成为2410上最为普遍的选择了。

 
   

   
网友: bob_zhang2004 时间:2007-11-14 10:29:22 IP地址:58.211.114.★
 
 
 

明白了, 原来是没有写出来啊, 怪不得。 

这回明白了 Fin 是什么意思, 之前只是知道肯定是 12MHz , 但就是不知道什么意思, 呵呵。 

多谢了。 
 
   

   
网友: 时间:2007-11-22 13:07:37 IP地址:202.199.138.★
 
 
 

科研的精神和乐于助人的精神都值得学习,非常感谢!  
 
   

   
网友: scanmiss 时间:2007-11-22 16:35:17 IP地址:218.5.3.★
 
 
 

hi, 这两个礼拜几乎每天都来,有关vivi的理解得真的不错,我现在也在写一个s3c2410的bootloader, 但是出现问题了,我用的是nor flash, sdram 64M,地址为0x30000000, 从0x30000000-0x3020000用做显示缓冲及其他功能, kernel (2.6.22)放在0x3020000+0x8000的地方, kernel参数放在0x3020000+0x100的地方,跳转到0x3020000+0x8000后就一点消息都没有,不知道是怎么回事?窜口连一点信息都不给,(提示信息到跳转到内核之前,之后的就没有了),是不是内核只能放在0x30000000,或者在什么地方有设这个值的?  

Blog作者的回复:
内核默认是解压到mem_base+0x8000处。而这个mem_base没有通过bootloader的参数导入(参数只会导入mem的大小,默认情况下,mem_base是固定的)。所以,如果一定要在0x30200000,就需要修改内核的代码了。

 
   

   
网友: scanmiss 时间:2007-11-22 17:46:35 IP地址:218.5.3.★
 
 
 

谢谢你的回复,
刚才我把kernel放在0x3000000的地方,但窜口也还是一点信息都没有,
我用make zImage做的内核zImage下载到nor flash, 在启动内核之前,我把mem_base+0x8000(0x30000000+0x8000)的数据打印出来如下:
e1a00000                e1a00000                e1a00000                e1a00000
e1a00000                e1a00000                e1a00000                e1a00000
ea000002                016f2818                00000000                0016b184
e1a07001                e1a08002                e10f2000                e3120003
1a000001                e3a00017                ef123456                e10f2000
e38220c0                e121f002                00000000                00000000
e28f00d0
和zImage的内容相同,窜口我用的参数传入(这用的是tag 的方式"console=ttySAC0,115200n8", 用param_struct时用的是" "noinitrd  console=ttySAC0"") 两者都不行,我用的是ADS 1.2 开发的,由于对汇编不熟,基本上是用vivi的汇编代码.
启动的代码如下:____________________________________________________
int boot_kernel(ulong from, size_t size, int media_type)
{
        int ret;
        int i;
        ulong boot_mem_base;    /* base address of bootable memory */
        ulong to;
        ulong mach_type;
        
        void (*call_linux)(int zero, int arch, unsigned long params_addr) = 
          (void (*)(int, int, unsigned long))(LINUX_KERNEL_BASE + LINUX_KERNEL_OFFSET);

        boot_mem_base = LINUX_KERNEL_BASE;

    /* copy kerne image */
        to = boot_mem_base + LINUX_KERNEL_OFFSET;

        DBGMSG(DEBUG, ("Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",
                from, to, size));

        ret = copy_kernel_img(to, (char *)from, size, media_type);

        if (ret) 
        {
                DBGMSG(DEBUG, ("failed/n"));
                return -1;
        } 
    else 
        {
                DBGMSG(DEBUG, ("done/n"));
        }

        if (*(ulong *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) 
        {
                DBGMSG(DEBUG, ("Warning: this binary is not compressed linux kernel image/n"));
                DBGMSG(DEBUG, ("zImage magic = 0x%08lx/n", *(ulong *)(to + 9*4)));
        } 
        else 
        {
                DBGMSG(DEBUG, ("zImage magic = 0x%08lx/n", *(ulong *)(to + 9*4)));
        }

         /* Setup linux parameters and linux command line */
        setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);

        /* Get machine type, see arch/arm/tools/mach-types */
        mach_type = MACH_TYPE;

        DBGMSG(DEBUG, ("MACH_TYPE = %d/n", mach_type));

        /* Go Go Go */
        DBGMSG(DEBUG, ("NOW, Booting Linux....../n"));
        clean_before_call_linux();
        
        DBGMSG(DEBUG, ("Maybe we can check some date!addr:0x%08lx /n", to));
        
        for(i = 0; i < 100; )
        {
            DBGMSG(DEBUG, ("%08lx        ", *(ulong *)(to + i)));
            i = i + 4;    
            if(i%16 == 0)
            {
                 DBGMSG(DEBUG, ("/n"));
            }
        }
        
        call_linux(0, mach_type, (unsigned long)(boot_mem_base + LINUX_PARAM_OFFSET));        

        DBGMSG(DEBUG, ("If here, error!/n"));
        
        return 0;   
}
______________________________________________________

Blog作者的回复:
命令行传递参数加上mem=64M。我在使用uboot的时候发现,如果不加入mem,则2.6.22的内核引导后,串口没有任何输出。

 
   

   
网友: scanmiss 时间:2007-11-22 18:03:12 IP地址:218.5.3.★
 
 
 

晕倒,我的机器上有4个窜口,我用的窜口是"console=ttySAC1,115200n8"
刚才才恍然大悟,我没有用mem=64M

Blog作者的回复:
只用115200就可以了。默认就是8n1的模式。

 
   

   
网友: scanmiss 时间:2007-11-22 18:52:35 IP地址:218.5.3.★
 
 
 

我把地址改成0x30200000后,果然内核就起不来了,
但是程序是跳转到0x30200000执行啊,机器码一个一个读进来执行,放在什么地方没什么关系吧?还是内核找不到参数表,所以就起不来了?

Blog作者的回复:
看看vivi开发笔记17,再读读lufuchong的bootm解析。
zImage bin文件分为三个部分,实现自解压。搬移地址是非常重要的,不能发生冲突。
这个地方与内核是相关的,并不是boot loader单方面的事情。

 
   

   
网友: tianhao_1983 时间:2007-12-18 11:19:17 IP地址:221.11.46.★
 
 
 

这里交流的好热闹呀,看到这么多的人有如此互相学习互相帮助的积极性,真是高兴,希望向calmarrow请教学习!!  
 
   

   
网友: 不死书生 时间:2008-01-01 21:17:19 IP地址:60.191.189.★
 
 
 

中国人如果多一点像你这样的人,那是中国的幸事,少一点浮华,多一点实在,中国的未来就要靠你们这样的人来支撑着。  

Blog作者的回复:
过誉了,只是安心做自己的事情

 
   

   
网友: 低调 时间:2008-04-19 17:16:09 IP地址:60.22.211.★
 
 
 

哥们,问一下。vivi的makefile中的

init/ version.o: init/ version.c include/compile.h
    $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/ version.o init/ version.c

其中的 -DUTS_MACHINE  是什么意思啊?   是给$(CC) 的参数吗?   

是arm体系的意识吧?
可是$(CC) 已经定义成arm-linux-gcc了  还要给它传递体系吗?   
为什么编译hello.c等简单的程序时,不用这个-DUTS_MACHINE  呢?
多谢!

Blog作者的回复:
man gcc ==> -D name=define

 
   

   
网友: 低调 时间:2008-04-20 11:19:33 IP地址:60.22.214.★
 
 
 


ifdef CONFIGURATION
..$(CONFIGURATION):
    @echo
    @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
    @echo
    $(MAKE) $(CONFIGURATION)
    @echo
    @echo "Successful. Try re-making (ignore the error that follows)"
    @echo
    exit 1

dummy:

else

dummy:

endif

这是vivi的makefile中的代码
请问..$(CONFIGURATION)中的那个".."是什么意思啊?谢谢

Blog作者的回复:
可以把该定义规则删除,没有用处

 
   

   
网友: 本站网友 时间:2008-04-22 16:14:55 IP地址:218.104.217.★
 
 
 

vivi 请教您一个关于重定位的问题,
例如现在我有三个数据段运行顺序为
.data
.bss
.text
 
其中.text为重定位段,被定位到.data后面。
实际的内存存放位置为
.data
.text
.bss
 
我们在执行链接脚本计算.bss段起始地址大小时需要知道它前面一段的大小就是.text段的大小,但这个时候我们还不能使用SIZEOF(.text)来计算。链接的时候就会报错,请问您有没有什么好办法解决这个问题。就是在执行脚本语言的时刻可不可以在没有定义.text段时就在前面引用它, 谢谢了 。
 
 
   

   
网友: 本站网友 时间:2008-04-22 16:19:08 IP地址:218.104.217.★
 
 
 

CalmArrow其实我问的问题主要就是LD在执行脚本语言时只进行一次链接可不可以先计算出每个数据段的大小,然后在根据这些大小以及我们配置的运行与加载顺序生成一个二进制文件??? 谢谢了 呵呵   

Blog作者的回复:
我认为这个问题的解决方案是按照内存的顺序编写好链接规则,这样可以通过定义的段的起始地址和终止地址得到段的位置和大小,然后增加一个搬移代码,完成搬移就可以了吧。
AT91RM9200提供的boot就是这种思路。
读一下http://blog.chinaunix.net/u/21948/showart_481779.html,会有帮助。
希望能够解决你的问题。

 
   

   
网友: 低调 时间:2008-04-25 23:38:13 IP地址:60.22.202.★
 
 
 

首先,感谢CalmArrow前面两个问题的回复。
这两天被vivi的分区弄得晕头转向,在网上找了些文章还是有点晕。
能帮我们讲讲vivi分区,part show看到的分区,bon分区,mtd分区到底都是 干什么的吗?为什么 还要通过bon命令重新设置分区呢?  不能 在vivi源代码中改写吗?   多谢了:)

Blog作者的回复:
采用bon分区主要是为了把分区表信息传递给内核,这样内核就不需要再次配置分区表。通信是双方的,所以内核必须有对bon分区的支持,具体的传递方式则是约定为最后一个分区的最后16KB区域作为共享区域来实现的。具体比较复杂,自己读下源代码吧。

 
   

   
网友: 低调 时间:2008-04-26 11:34:36 IP地址:60.23.123.★
 
 
 

请问斑竹:
vivi的bon分区是干什么的?
为什么我无论怎么使用bon 命令“胡乱”分区,内核也能照样运行,而且yaffs文件系统也能照样运行呢?
多谢!

Blog作者的回复:
你的内核应该采用了MTD分区,而不是bon分区。

 
   

   
网友: 低调 时间:2008-05-03 09:56:39 IP地址:60.22.213.★
 
 
 

感谢!  
 
   

   
网友: 低调 时间:2008-05-03 13:49:40 IP地址:60.22.213.★
 
 
 

vivi都向内核传递了什么?
我先把我理解的都列出来,缺的和错的,请 CalmArrow和诸位兄弟帮补充一下,谢谢。
1,传递了param_struct。
    (1)page_size。为什么要传递这个呢?是因为vivi中设置的那个页表映射吗?这个页表映射kernel也要使用吗?kernel中不也会重新设置页表吗?
    (2)nr_pages。  
     (3)commandline 。内核启动的时候,使用哪个串口打印信息是由commandline中的“console=?”决定的吗?
2,传递了machine type通过设置r1.
3,设置了r1=0.为什么呀?
4,为什么没有传递media_type?内核怎么知道文件系统是在nand中还是在其他地方?
5,内核和vivi都有哪些约定?
    (1)内核和vivi的MTD分区要一致。
    (2)zImage一定要放在mem_base+0x8000处吗?
    (3)param_struct也要放在那个固定位置吗?

哈哈,我扔一块砖头  ,等着CalmArrow和诸位兄弟的玉哦:)

  
   
 
   

   
网友: joshuazzh 时间:2008-06-27 10:18:01 IP地址:222.35.60.★
 
 
 

看到您的博客如此有条理、思路清晰,自己真觉得自惭形秽!
您给我做了好榜样
见贤思齐,见不贤而内自醒!
谢谢你
我研究生入学马上一年了,这学期开始刚接触linux,到现在做过的工作有在恒颐H2410F的开发板上移植vivi、移植2.6.14.1内核、制作cramfs和yaffs文件系统、编写简单的脚本文件、在板子上进行串口网口socket编程,实现UATR1接收到的数据通过网口发送至internet远端主机等一些工作
做完之后没有好好整理思路笔记,现在自己都有很多记不清了
我是伴随您的博客一起学习linux的,
从入门到现在经常光顾您的博客,
第一次给您留言,
以后还有很多问题向您请教!
 
   

   
网友: 本站网友 时间:2008-08-06 16:54:59 IP地址:218.104.217.★
 
 
 

CalmArrow您好
请教您个问题,我们的开发环境原来GCC的版本用的是3.4.4现在换成用2.95.2在编译同一个工程的时候他在链接的时候报错:
错误消息如下:E:/host/acoreos2x/arch/x86/bin/dcore-ld: final link failed: Bad value
make: *** [E/target/workspace/os/i386_le_soft_debug/make/os.elf] Error 1
make: Target `all' not remade because of errors.

请问是不是2.9与3.4所执行的ld脚本有区别?谢谢
 
   

   
网友: clf1985 时间:2008-08-15 12:54:19 IP地址:58.39.1.★
 
 
 

从今天开始,学习你的贴子。写的很好,思路很清晰。  
 
   

   
网友: NEWCOMER 时间:2008-08-22 13:47:54 IP地址:219.128.48.★
 
 
 

BON分区是老式的,基本没用;MTD分区是存放系统文件的。
现在分区的时候采用bon, 安装系统时实际是yaffs, bon算是辅助性的。你可以看vivi源代码。vivi.tgz
以上也是网上找来的.但是加进去你的文章可以解释BON 和MTD的问题
 
   

   
网友: agela 时间:2008-09-28 14:10:52 IP地址:123.127.134.★
 
 
 

你的timer那块怎么没什么说明啊,能说说timer吗?  
 
   

   
网友: 本站网友 时间:2009-03-24 00:29:12 IP地址:202.122.32.★
 
 
 

步骤一:下载VIVI源码

步骤二: 修改Makefile 里面的3个编译量

编译成功生成vivi

步骤三:sjf2410下载 vivi  

显示结果:

@000000E8
OK  
00000054
00ABEA00
FAIL

经过多天的追踪,发现是VIVI的

copy_myself 程序 复制 128K到 sdram 的0x33f00000 地址之后 跳转到

ok_nand_read程序下 进行4K的二进制代码比较,

比较 中 由于 sdram 与 sram 里面的不一样 跳入 notmatch程序 

得到的问题:

1,是sdram的问题,还是sjf2410写bin文件写的就是错的?

2,如果sjf2410写没有错误,那么可能就是nand_read.c文件里面的nandflash读程序有问题?

3,如果sjf2410写没错,nand_read.c里面的nand_read_ll()也没问题

那我的问题在那里呢?

郁闷呀!!!!!!!!!!!!!

希望得到高手指点
 
   

   
网友: liuyan546 时间:2009-05-14 18:35:33 IP地址:221.0.91.★
 
 
 

看了你学习vivi的这第一章我就有种仰视的感觉,也感受到了作为一个技术员的差距,向你学习,首先是做人做事的态度。谢谢,让我知道了自己的缺陷和目标。。希望在有生之年能让自己有资格拜见一下前辈  
 
   

   
网友: 本站网友 时间:2009-08-13 11:20:39 IP地址:219.133.141.★
 
 
 

X  
 
   

   
网友: 本站网友 时间:2009-08-13 11:21:47 IP地址:219.133.141.★
 
 
 

你好!关于VA-->MVA的问题我还是不明白,总觉得利用PID生成MVA的方法没什么太大的实际意义。就算在小于32M是成立的,但大于32M呢,也会出现重叠VA的现象啊!搞不懂,请赐教!  
 
   

   
网友: 本站网友 时间:2009-10-14 00:26:20 IP地址:121.249.204.★
 
 
 

关于GPIO试验的确是非常简单,但也有要注意的问题,比如:启动代码后缀的s要大写,即init.S,如果是小写会提示找不到_start入口。另外,从这个简单的例子也可以看出编译语言的高效性,实现相同功能的代码,执行的效率简直是天壤之别。  
 
   

   
网友: qiudeyezi 时间:2009-10-20 15:33:43 IP地址:58.248.224.★
 
 
 

你好!我最近读了您的文章,我尝试将viv移植到s3c2440的开发板上,编译成功后,串口只打印了一句"Starting application at 0x30000000...“这句话就完全没反应了,我从网上另外找了一个2440的vivi源码编译过后却可以看到启动信息,我发现这两个源码的vivi.lds是不相同的,是否是这个原因?请指教,感谢!  
 
   

   
网友: feitian0896 时间:2010-04-08 16:14:39 IP地址:61.191.26.★
 
 
 

仔细看了你的文章。很不错。有个疑问,不知道是笔误还是其他。你有这么一段话。
##虽然bl 30000040 <memsetup>是30000040,但是要注意,此处指令为bl,所以只能相对寻址,而不能够绝对寻址,也就是说,它只能跳转到距离0x30000000为0x40的位置,这点查看bl的汇编指令说明就比较清晰了。##

最后一句话,这个应该是跳转到距离0x00000000为0x40的位置。因为相对寻址是相对于pc的。此时pc应为0x00000000.
memsetup是个绝对地址。bl会把这个地址左移2位当成偏移量来加上pc的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

bootloader开发阶段总结以及可能会碰到的问题 的相关文章

  • http digest认证(Java server)

    背景 xff1a 服务器接收客户端请求 xff0c 处理并验证 并返回服务器的验证结果 关于digest认证的相关概念及验证原理查看相关的说明 xff0c 此处只对处理进行贴码 CODE import com alibaba fastjso
  • 测试apache时出现[error] [client 192.168.6.1] File does not exist: /etc/httpd/htdocs

    问题 xff1a 测试apache时出现 error client 192 168 6 1 File does not exist etc httpd htdocs 解决方法 xff1a 1 创建文件夹htdocs xff08 etc ht
  • HAL库 STM32 串口通信函数

    HAL UART Receive IT串口 xff01 HAL UART Receive IT amp UART1 Handler u8 aRxBuffer RXBUFFERSIZE HAL UART Receive IT函数使用的时候 简
  • linux环境下安装QT超详细

    QT安装 1 首先下载QT安装包 QT官网 xff1a Index of archive qt 我这里使用的是qt opensource linux x64 5 14 0 run版本 2 打开终端 xff0c 输入命令 xff0c 赋予安装
  • 使用ssh连接虚拟机保姆级教程

    首先安装SSH 安装先检测是否已经安装SSH xff1a service ssh status 如果出现提示 xff1a ssh unrecognized service 说明没有安装openSSH xff0c 则需安装ssh SSH 服务
  • 小游戏2048设计思路超简单

    2048作为一个经典的小游戏 xff0c 对于C语言的逻辑练习是一个比较好的案例了 xff0c 看似很复杂 xff0c 但是如果掌握了设计思路 xff0c 那么就不会觉得难了 xff0c 而且会了这个之后对今后编程的也会有很大的帮助 先分析
  • ES-Elasticsearch查看所有索引及查看某索引下的信息

    1 查看所有索引 xff0c 地址栏直接访问下面的连接 http localhost 9200 cat indicesv amp pretty 2 查看某索引下存的信息 xff0c 查询的信息为索引结构信息 xff08 indexName为
  • 教你十分钟搭建博客,已在多台电脑测试,无坑

    1 前期工作 1 注册Github账号 官网地址 xff1a GitHub 2 下载安装git Git软件下载地址 xff1a Git Downloading Package git scm com 安装的话一直点next就可以了 3 绑定
  • MQTT使用TLS加密

    使用TLS加密在MQTT的使用中是比较常见的 xff0c TLS加密过程在网上有很多说明 xff0c 但是没几个应用教程的 xff0c MQTT软件中的EMQX软件是支持TLS加密的 xff0c 只不过要进行一些设置 安装EMQX软件 首先
  • linux下将QT移植至arm环境

    前言 讲下整个项目流程 xff0c 我们的目标是把qt编出来程序放在arm开发板上面跑 xff0c 首先下载QT源码和tslib源码 xff08 QT源码编译和QT程序运行需要tslib库的支持 xff09 xff0c 在虚拟机里使用交叉编
  • linux下移植onvif至arm环境

    前言 onvif是一种网络摄像头协议 xff0c linux网络摄像头这一块是需要移植onvif协议的 xff0c 整个移植过程是这样的 xff0c 首先onvif协议是依赖于gsoap的 xff0c 所以需要先将gsoap编译安装 xff
  • C语言使用二级指针实现字符串分割

    话不多说 xff0c 直接上代码 include lt stdio h gt int opt char p char ch char res char q 61 p if q 61 61 NULL q 61 61 39 0 39 retur
  • 已include包却提示未定义标识符

    已 include lt string gt xff0c include lt vector gt 却提示string xff0c vector未定义的标识符 因为没定义默认的命名空间 xff0c 改为std string xff0c st
  • jpg和png的区别小结

    png图像的大小是jpg图像大小的数倍 xff0c png为可移植网络图形格式 xff0c 也是一种位图文件存储格式 xff0c 可以进行无损压缩 xff0c jpg是最常见的图像格式 xff0c 图像占用的存储较小 xff0c 但是牺牲了
  • 色彩空间中的HSL、HSV、HSB有什么区别?

    作者 xff1a 大蔚陈 链接 xff1a https www zhihu com question 22077462 answer 29483467 来源 xff1a 知乎 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非商业
  • opencv小程序练习——createBackgroundSubtractorMOG2()实现跟踪

    思想 xff1a 使用createBackgroundSubtractorMOG2 使用运动物体背景分割 使用findContours 查找轮廓并画出 实现一定感官上的跟踪功能 代码如下 xff1a include lt opencv2 o
  • opencv_tutorial_code学习——canny边缘检测后findContours

    tutorial code ShapeDescriptors findContours demo cpp 步骤 xff1a 1 灰度化 2 滤波 3 canny边缘检测 4 findContours canny output contour
  • idea开发工具右侧没有maven工具栏

    一 解决方式一 依次点击 View gt Tool Windows gt Maven xff0c 如下图 xff1a 二 解决方式二 点击如图所示IDEA界面最左下角的按钮 xff0c 如下图 xff1a 三 解决方式三 1 打开项目的 p
  • 语义分割与实例分割的区别

    目前的分割任务主要有两种 xff1a xff08 1 xff09 像素级别的语义分割 xff08 2 xff09 实例分割 这个有意思 xff0c 什么叫实例分割呢 xff1f 它与语义分割有什么区别与联系呢 xff1f 顾名思义 xff0
  • tiny-dnn配置运行

    tiny dnn是一个轻量级的CNN xff08 卷积神经网络 xff09 xff0c 不需要各种依赖和GPU xff0c 由三千多行C 43 43 代码完成 适配android平台的话 xff0c 感觉这个比较好做一点 下载地址 xff1

随机推荐

  • SSM笔记

    进入数据库 xff1a 34 D Program Files x86 mysql 5 7 20 winx64 bin mysql exe 34 u root p admin 展示数据库 xff1a show databases 创建数据库
  • 工程编译那点事:Makefile和cmake(一)

    makefile 前言Makefile介绍 Makefile规则make是如何工作的Makefile使用变量让make自动推导另类风格的Makefilemake中的函数文件搜索绝对顶级的大型工程Makefile 前言 一个项目 xff0c
  • 头文件相互包含问题

    先来看看以下这个例子 xff1a Keyboard h的代码为 span class token macro property span class token directive hash span span class token di
  • 解决roslaunch启动stage_ros节点仿真时输出rostopic hz速率较低的问题(始终为10Hz)

    问题描述 xff1a 在实验过程中偶然间发现无论是odom还是laser scan的输出频率都只有10Hz clock输出速率有50Hz 直接使用命令 rosrun stage ros stageros test world能够正常输出50
  • STM32八种IO口模式区别

    xff08 1 xff09 GPIO Mode AIN 模拟输入 xff08 2 xff09 GPIO Mode IN FLOATING 浮空输入 xff08 3 xff09 GPIO Mode IPD 下拉输入 xff08 4 xff09
  • linux下C++实现Http请求类(GET,POST,上传,下载)

    linux下C 43 43 实现Http请求类 GET xff0c POST xff0c 上传 xff0c 下载 Http协议简述 协议 xff1a 网络协议的简称 xff0c 网络协议是通信计算机双方必须共同遵从的一组约定 如怎么样建立连
  • 正点原子MiniFly V1.2学习笔记四---txQueue队列数据哪来

    笔记二的第四点中 xff0c 把解包出来的指令发送到 rxQueue队列里 xff0c 然后从txQueue队列取数据发送到串口 那么txQueue队列的数据从哪里来的 一 txQueue数据从哪里来 xff1f 二 什么地方会调用radi
  • redis链接工具

    redis链接工具 今天推荐一款redis链接工具 xff0c 其实世面上连接redis的工具很多 xff0c 但是好用的很少 例如 xff1a redis desktop manager这款工具也不错 xff0c 但是我个人不能使用 xf
  • Linux 网络编程——UDP编程

    一 概述 UDP 是 User Datagram Protocol 的简称 xff0c 中文名是用户数据报协议 xff0c 是一个简单的面向数据报的运输层协议 xff0c 在网络中用于处理数据包 xff0c 是一种无连接的协议 UDP 不提
  • 给指定的寄存器地址:0x0001eea7 ,赋值

    coretexM0平台上给指定的寄存器地址 xff1a 0x0001eea7 赋值100 怎么实现 xff1f xff08 volatile char xff09 0x0001eea7 61 100 xff1b 常见错误1 xff1a xf
  • 常见cmake命令总结

    常见cmake命令总结 cmake常见命令 cmake minimum required 指定CMake的最小版本要求 cmake minimum required VERSION 2 8 project 定义工程名称 project PR
  • 利用Qt Phonon框架制作音视频播放器

    Phonon严格来说其实非为Qt的library xff0c Phonon原本就是KDE 4的开放源代码多媒体API xff0c 後来与Qt合并与开发 xff0c 所以简单来说就是Qt使用Phonon这个多媒体框架来提供一般影音多媒体档案的
  • 主设备号和次设备号

    Linux的设备管理是和文件系统紧密结合的 xff0c 各种设备都以文件的形式存放在 dev目录下 xff0c 称为设备文件 应用程序可以打开 关闭和读写这些设备文件 xff0c 完成对设备的操作 xff0c 就像操作普通的数据文件一样 为
  • Makefile中的wildcard用法

    在Makefile规则中 xff0c 通配符会被自动展开 但在变量的定义和函数引用时 xff0c 通配符将失效 这种情况下如果需要通配符有效 xff0c 就需要使用函数 wildcard xff0c 它的用法是 xff1a wildcard
  • GPIO

    一 什么是GPIO xff1f 首先应该理解什么是GPIO GPIO xff0c 英文全称为General Purpose IO ports xff0c 也就是通用IO口 在嵌入式系统中常常有数量众多 xff0c 但是结构却比较简单的外部设
  • UART

    一 S3C2410内置的UART控制器 S3C2410内部具有3个独立的UART控制器 xff0c 每个控制器都可以工作在Interrupt xff08 中断 xff09 模式或DMA xff08 直接内存访问 xff09 模式 xff0c
  • vivi源代码最为详细分析(二)

    现在进入bootloader之vivi分析的第二阶段 xff0c 这部分使用C语言实现 xff0c 部分代码采取内嵌汇编的方式 这里需要用到GNU GCC内嵌汇编 的知识 xff0c 这部分基础还没有具备 xff0c 需要学习 下面先按照流
  • vivi源代码最为详细分析(三)

    step 5 xff1a MTD设备初始化 关于什么是MTD xff0c 为什么要使用MTD xff0c MTD技术的架构是什么 xff0c 等等 xff0c 可以参考 Linux MTD源代码分析 xff08 作者 xff1a Jim Z
  • 【笔记】docker-compose.yml 文件更改后重新启动加载更改后的内容

    docker compose yml 文件更改后想使之立刻生效 xff0c 但是不想手动删除已经建立的 container 等信息可以运行下面命令 重新创建容器实现修改 docker compose up force recreate d
  • bootloader开发阶段总结以及可能会碰到的问题

    到今天 xff0c vivi源代码基本分析完毕 对bootloader有了更深层的认识 在此期间 xff0c 仔细阅读了毛德操 胡希明先生编著的 嵌入式系统 采用公开源代码和StrongARM XScale处理器 第七章 xff1a 嵌入式