如何启动内核vivi与Linux kernel的参数传递情景分析.docx

上传人:b****5 文档编号:6099279 上传时间:2023-01-03 格式:DOCX 页数:20 大小:36.71KB
下载 相关 举报
如何启动内核vivi与Linux kernel的参数传递情景分析.docx_第1页
第1页 / 共20页
如何启动内核vivi与Linux kernel的参数传递情景分析.docx_第2页
第2页 / 共20页
如何启动内核vivi与Linux kernel的参数传递情景分析.docx_第3页
第3页 / 共20页
如何启动内核vivi与Linux kernel的参数传递情景分析.docx_第4页
第4页 / 共20页
如何启动内核vivi与Linux kernel的参数传递情景分析.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

如何启动内核vivi与Linux kernel的参数传递情景分析.docx

《如何启动内核vivi与Linux kernel的参数传递情景分析.docx》由会员分享,可在线阅读,更多相关《如何启动内核vivi与Linux kernel的参数传递情景分析.docx(20页珍藏版)》请在冰豆网上搜索。

如何启动内核vivi与Linux kernel的参数传递情景分析.docx

如何启动内核vivi与Linuxkernel的参数传递情景分析

vivi开发笔记(十七):

vivi与Linuxkernel的参数传递情景分析(上)

在上一部分提到过了,vivi作为bootloader,向内核传递启动参数是其本职工作之一。

要把这个情景分析清楚,不仅仅需要分析vivi的参数机制,而且要分析Linuxkernel的接收机制。

因为这是一个简单的通信过程,比起本科所学习的TCP/IP来简单的多,但是因为简单,所以在协议上并不规范,理解上反而不如TCP/IP协议。

下面就分为两个方面对此情景分析。

一、综述内核参数传递机制

  现在内核参数传递机制有两种:

一种是基于structparam_struct,这种已经比较老了。

缺点是该结构每个成员的位置是固定的,受限比较大。

另外一种就是新的structtagway。

说新是相对的,Linuxkernel2.4.x都希望采用这种tag的方式。

关于这方面的资料,可以有如下参考(所给出的目录是基于linux-2.4.18的内核,以顶层Makefile所在目录为当前目录。

这里基于ARM架构的S3C2410,其他的SoC可以类比很容易得到):

1、关于bootloader的理解--【Documentation/arm/booting】

  此文档详细的讲述了bootloader的作用,具体内容如下:

[armlinux@lqmarm]$catBooting

                BootingARMLinux

                =================

Author:

RussellKing

Date:

18May2002

Thefollowingdocumentationisrelevantto2.4.18-rmk6andbeyond.

InordertobootARMLinux,yourequireabootloader,whichisasmall

programthatrunsbeforethemainkernel.Thebootloaderisexpected

toinitialisevariousdevices,andeventuallycalltheLinuxkernel,

passinginformationtothekernel.

Essentially,thebootloadershouldprovide(asaminimum)the

following:

1.SetupandinitialisetheRAM.

2.Initialiseoneserialport.

3.Detectthemachinetype.

4.Setupthekerneltaggedlist.

5.Callthekernelimage.

1.SetupandinitialiseRAM

---------------------------

Existingbootloaders:

MANDATORY

Newbootloaders:

MANDATORY

ThebootloaderisexpectedtofindandinitialiseallRAMthatthe

kernelwilluseforvolatiledatastorageinthesystem.Itperforms

thisinamachinedependentmanner.(Itmayuseinternalalgorithms

toautomaticallylocateandsizeallRAM,oritmayuseknowledgeof

theRAMinthemachine,oranyothermethodthebootloaderdesigner

seesfit.)

2.Initialiseoneserialport

-----------------------------

Existingbootloaders:

OPTIONAL,RECOMMENDED

Newbootloaders:

OPTIONAL,RECOMMENDED

Thebootloadershouldinitialiseandenableoneserialportonthe

target.Thisallowsthekernelserialdrivertoautomaticallydetect

whichserialportitshoulduseforthekernelconsole(generally

usedfordebuggingpurposes,orcommunicationwiththetarget.)

Asanalternative,thebootloadercanpasstherelevant'console='

optiontothekernelviathetaggedlistsspecifingtheport,and

serialformatoptionsasdescribedin

    linux/Documentation/kernel-parameters.txt.

3.Detectthemachinetype

--------------------------

Existingbootloaders:

OPTIONAL

Newbootloaders:

MANDATORY

Thebootloadershoulddetectthemachinetypeitsrunningonbysome

method.Whetherthisisahardcodedvalueorsomealgorithmthat

looksattheconnectedhardwareisbeyondthescopeofthisdocument.

ThebootloadermustultimatelybeabletoprovideaMACH_TYPE_xxx

valuetothekernel.(seelinux/arch/arm/tools/mach-types).

4.Setupthekerneltaggedlist

-------------------------------

Existingbootloaders:

OPTIONAL,HIGHLYRECOMMENDED

Newbootloaders:

MANDATORY

Thebootloadermustcreateandinitialisethekerneltaggedlist.

AvalidtaggedliststartswithATAG_COREandendswithATAG_NONE.

TheATAG_COREtagmayormaynotbeempty.AnemptyATAG_COREtag

hasthesizefieldsetto'2'(0x00000002).TheATAG_NONEmustset

thesizefieldtozero.

Anynumberoftagscanbeplacedinthelist.Itisundefined

whetherarepeatedtagappendstotheinformationcarriedbythe

previoustag,orwhetheritreplacestheinformationinits

entirety;sometagsbehaveastheformer,othersthelatter.

Thebootloadermustpassataminimumthesizeandlocationof

thesystemmemory,androotfilesystemlocation.Therefore,the

minimumtaggedlistshouldlook:

      +-----------+

base->|ATAG_CORE||

      +-----------+|

      |ATAG_MEM||increasingaddress

      +-----------+|

      |ATAG_NONE||

      +-----------+v

ThetaggedlistshouldbestoredinsystemRAM.

Thetaggedlistmustbeplacedinaregionofmemorywhereneither

thekerneldecompressornorinitrd'bootp'programwilloverwrite

it.Therecommendedplacementisinthefirst16KiBofRAM.

5.Callingthekernelimage

---------------------------

Existingbootloaders:

MANDATORY

Newbootloaders:

MANDATORY

TherearetwooptionsforcallingthekernelzImage.IfthezImage

isstoredinflash,andislinkedcorrectlytoberunfromflash,

thenitislegalforthebootloadertocallthezImageinflash

directly.

ThezImagemayalsobeplacedinsystemRAM(atanylocation)and

calledthere.Notethatthekerneluses16KofRAMbelowtheimage

tostorepagetables.Therecommendedplacementis32KiBintoRAM.

Ineithercase,thefollowingconditionsmustbemet:

-CPUregistersettings

  r0=0,

  r1=machinetypenumberdiscoveredin(3)above.

  r2=physicaladdressoftaggedlistinsystemRAM.

-CPUmode

  Allformsofinterruptsmustbedisabled(IRQsandFIQs)

  TheCPUmustbeinSVCmode.(AspecialexceptionexistsforAngel)

-Caches,MMUs

  TheMMUmustbeoff.

  Instructioncachemaybeonoroff.

  Datacachemustbeoff.

-Thebootloaderisexpectedtocallthekernelimagebyjumping

  directlytothefirstinstructionofthekernelimage.

  可以看出bootloader最少具备5项功能,上面比较清晰。

可以看出,现在2.4的内核都是希望采用taggedlist的方式来进行传递的,这里没有提到比较老的方式。

这里要特别注意的是,r2=physicaladdressoftaggedlistinsystemRAM.,这里的“必须”是针对于taggedlist而言的,如果采用param_struct,则并没有这个限制。

这在后面将会详细分析,而这正是可能导致疑惑的地方。

2、参数传递数据结构的定义位置【include/asm/setup.h】,在这里就可以看到两种参数传递方式了。

可以说,现在bootloader和Linuxkernel约定的参数传递机制就是这两种,必须严格按照这两种机制进行传输,否则的话,kernel可能因为无法识别bootloader传递过来的参数而导致无法启动。

关于这两种方式,在这里还有说明:

/*

*linux/include/asm/setup.h

*

*Copyright(C)1997-1999RussellKing

*

*Thisprogramisfreesoftware;youcanredistributeitand/ormodify

*itunderthetermsoftheGNUGeneralPublicLicenseversion2as

*publishedbytheFreeSoftwareFoundation.

*

*Structurepassedtokerneltotellitaboutthe

*hardwareit'srunningon.Seelinux/Documentation/arm/Setup

*formoreinfo.

*

*NOTE:

*Thisfilecontainstwowaystopassinformationfromtheboot

*loadertothekernel.Theoldstructparam_structisdeprecated,

*butitwillbekeptinthekernelfor5yearsfromnow

*(2001).Thiswillallowbootloaderstoconverttothenewstruct

*tagway.

*/

  这说明,现在参数传递必须要采用tag方式,因为现在新的kernel已经不支持param_struct方式了。

不幸的是,vivi还是采用的param_struct方式。

这里暂时以param_struct为主分析,考虑以后更新为tag方式。

在这里你也可以参考【Documentation/arm/setup】,里面有关于选项具体含义的详细说明。

(在这里多说几句。

Linux的Documentation是一个很好的学习库,几乎所有的问题在这里都能有初步的解答。

如果要想继续深入,那么就要读源代码了。

学习上,先看README,然后翻阅Documentation,无疑是一条捷径。

而且,是否有完备的文档,也是判断这个软件是否优秀的重要标准。

二、vivi设置Linux参数分析

  上面对bootloader与Linuxkernel之间参数传递的两种方式已经有了一个总体的理解。

下面就来先看vivi部分如何设置Linux参数。

【init/main.c】boot_or_vivi()-->run_autoboot()-->exec_string("boot")

  到此,也就是要执行boot命令。

与命令相关部分都在【lib/command.c】中,找到boot_cmd,然后跟踪至【lib/boot_kernel.c】,boot的执行行为函数为command_boot(),继续分析:

【lib/boot_kernel.c】command_boot()-->

主要就是三步工作。

  ·获取media_type。

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

  media_type是重要的,因为对于不同的存储介质,底层的驱动函数是不同的。

通过media_type这个顶层抽象,实现了与底层驱动的联系。

[armlinux@lqminclude]$catboot_kernel.h

#ifndef_VIVI_BOOT_KERNEL_H_

#define_VIVI_BOOT_KERNEL_H_

/*

*MediaType:

Atypeofstoragedevicethatcontainsthelinuxkernel

*

*+----------------+-----------------------------------------+

*|Value(Integer)|Type|

*+----------------+-----------------------------------------+

*|0|UNKNOWN|

*|1|RAM|

*|2|NORFlashMemory|

*|3|SMC(NANDFlashMemory)ontheS3C2410|

*+----------------+-----------------------------------------+

*/

enum{

      MT_UNKNOWN=0,

      MT_RAM,

      MT_NOR_FLASH,

      MT_SMC_S3C2410

};

#endif/*_VIVI_BOOT_KERNEL_H_*/

  上面就是vivi支持的media_type,现在此开发板是MT_SMC_S3C2410,也就是nandflashmemory的选择部分。

  ·获取nandflash的kernel分区信息,为下载做好准备

kernel_part=get_mtd_partition("kernel");

                if(kernel_part==NULL){

                      printk("Can'tfinddefault'kernel'partition\n");

                      return;

                }

                from=kernel_part->offset;

                size=kernel_part->size;

  这里获得了kernel所在nandflash的起始地址和大小。

这里应该注意,虽然kernel_part->offset是偏移量,但是这个偏移是相对于0x00000000而言,所以这时的offset就是对应的起始地址。

当然,对nandflash来说,这里的地址并非是内存映射,需要做一系列的变化,具体是在nand_read_ll函数中,前面的基本实验已经做过了。

  ·启动内核

boot_kernel(from,size,media_type);

  利用前面得到的media_type,from,size就可以来启动内核了,当然还有多步工作要去做。

具体包括如下内容:

(1)获取内存基地址

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

  在vivi中,sdram是从0x30000000开始的,所以这里的boot_mem_base就是0x30000000.

(2)把kernel映象从nandflash复制到sdram的固定位置

  to=boot_mem_base+LINUX_KERNEL_OFFSET;

  printk("Copylinuxkernelfrom0x%08lxto0x%08lx,size=0x%08lx...",

      from,to,size);

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

  这里LINUX_KERNEL_OFFSET是0x8000,关于为什么是0x8000,这是历史原因造成的,是Linux内核的一个约定,具体可以查看Linux内核的源代码中的arch/arm/kernel/head_armv.S,如下:

/*

*Weplacethepagetables16KbelowTEXTADDR.Therefore,wemustmakesure

*thatTEXTADDRiscorrectlyset.Currently,weexpecttheleastsignificant

*"short"tobe0x8000,butwecouldprobablyrelaxthisrestrictionto

*TEXTADDR>PAGE_OFFSET+0x4000

*

*Notethatswapper_pg_diristhevirtualaddressofthepagetables,and

*pgtblgivesusaposition-independentreferencetothesetables.Wecan

*dothisbecausestext==TEXTADDR

*

*swapper_pg_dir,pgtblandkrnladrareallcloselyrelated.

*/

  可以看出,TEXTADDR就是stext的地址,本开发板上为0x30008000,在0x30008000往下,会放置16K的页表,预计是0x8000.不过此处可能会放松这个限制。

另外,我们的一些参数也会放到内存起始区域。

这在后面就可以看到。

总之,这个地方的位置boot_mem_base也就是kernel的第一条指令所在地,最后的程序跳转要跳到这个位置。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1