久久久久久久麻豆,中日韩av在线,麻豆av在线免费,中文字幕二区三区,欧美日韩视频一区二区,亚洲欧美日韩在线一区,国产无毒不卡

嵌入式系統(tǒng) Boot Loader 技術(shù)內(nèi)幕


嵌入式 linux 系統(tǒng)中,通常需要由 boot loader 設(shè)置的常見(jiàn)啟動(dòng)參數(shù)有:atag_core、atag_mem、atag_cmdline、atag_ramdisk、atag_initrd等。

比如,設(shè)置 atag_core 的代碼如下:

params = (struct tag *)boot_params;params->hdr.tag = atag_core;params->hdr.size = tag_size(tag_core);params->u.core.flags = 0;params->u.core.pagesize = 0;params->u.core.rootdev = 0;params = tag_next(params);

其中,boot_params 表示內(nèi)核啟動(dòng)參數(shù)在內(nèi)存中的起始基地址,指針 params 是一個(gè) struct tag 類(lèi)型的指針。宏 tag_next() 將以指向當(dāng)前標(biāo)記的指針為參數(shù),計(jì)算緊臨當(dāng)前標(biāo)記的下一個(gè)標(biāo)記的起始地址。注意,內(nèi)核的根文件系統(tǒng)所在的設(shè)備id就是在這里設(shè)置的。

下面是設(shè)置內(nèi)存映射情況的示例代碼:

for(i = 0; i < num_mem_areas; i++) {if(memory_map[i].used) {params->hdr.tag = atag_mem;params->hdr.size = tag_size(tag_mem32);params->u.mem.start = memory_map[i].start;params->u.mem.size = memory_map[i].size;params = tag_next(params);}}

可以看出,在 memory_map[]數(shù)組中,每一個(gè)有效的內(nèi)存段都對(duì)應(yīng)一個(gè) atag_mem 參數(shù)標(biāo)記。

linux 內(nèi)核在啟動(dòng)時(shí)可以以命令行參數(shù)的形式來(lái)接收信息,利用這一點(diǎn)我們可以向內(nèi)核提供那些內(nèi)核不能自己檢測(cè)的硬件參數(shù)信息,或者重載(override)內(nèi)核自己檢測(cè)到的信息。比如,我們用這樣一個(gè)命令行參數(shù)字符串"console=ttys0,115200n8"來(lái)通知內(nèi)核以 ttys0 作為控制臺(tái),且串口采用 "115200bps、無(wú)奇偶校驗(yàn)、8位數(shù)據(jù)位"這樣的設(shè)置。下面是一段設(shè)置調(diào)用內(nèi)核命令行參數(shù)字符串的示例代碼:

char *p;/* eat leading white space */for(p = commandline; *p == " "; p++);/* skip non-existent command lines so the kernel will still    * use its default command line. */if(*p == "\0")return;params->hdr.tag = atag_cmdline;params->hdr.size = (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;strcpy(params->u.cmdline.cmdline, p);params = tag_next(params);

請(qǐng)注意在上述代碼中,設(shè)置 tag_header 的大小時(shí),必須包括字符串的終止符"\0",此外還要將字節(jié)數(shù)向上圓整4個(gè)字節(jié),因?yàn)?tag_header 結(jié)構(gòu)中的size 成員表示的是字?jǐn)?shù)。

下面是設(shè)置 atag_initrd 的示例代碼,它告訴內(nèi)核在 ram 中的什么地方可以找到 initrd 映象(壓縮格式)以及它的大?。?

params->hdr.tag = atag_initrd2;params->hdr.size = tag_size(tag_initrd);params->u.initrd.start = ramdisk_ram_base;params->u.initrd.size = initrd_len;params = tag_next(params);

下面是設(shè)置 atag_ramdisk 的示例代碼,它告訴內(nèi)核解壓后的 ramdisk 有多大(單位是kb):

params->hdr.tag = atag_ramdisk;params->hdr.size = tag_size(tag_ramdisk);params->u.ramdisk.start = 0;params->u.ramdisk.size = ramdisk_size; /* 請(qǐng)注意,單位是kb */params->u.ramdisk.flags = 1; /* automatically load ramdisk */params = tag_next(params);

最后,設(shè)置 atag_none 標(biāo)記,結(jié)束整個(gè)啟動(dòng)參數(shù)列表:

static void setup_end_tag(void){params->hdr.tag = atag_none;params->hdr.size = 0;}

3.2.5 調(diào)用內(nèi)核

boot loader 調(diào)用 linux 內(nèi)核的方法是直接跳轉(zhuǎn)到內(nèi)核的第一條指令處,也即直接跳轉(zhuǎn)到 mem_start+0x8000 地址處。在跳轉(zhuǎn)時(shí),下列條件要滿足:

1. cpu 寄存器的設(shè)置:

  • r0=0;

  • r1=機(jī)器類(lèi)型 id;關(guān)于 machine type number,可以參見(jiàn) linux/arch/arm/tools/mach-types。

  • r2=啟動(dòng)參數(shù)標(biāo)記列表在 ram 中起始基地址;

2. cpu 模式:

  • 必須禁止中斷(irqs和fiqs);

  • cpu 必須 svc 模式;

3. cache 和 mmu 的設(shè)置:

  • mmu 必須關(guān)閉;

  • 指令 cache 可以打開(kāi)也可以關(guān)閉;

  • 數(shù)據(jù) cache 必須關(guān)閉;

如果用 c 語(yǔ)言,可以像下列示例代碼這樣來(lái)調(diào)用內(nèi)核:

void (*thekernel)(int zero, int arch, u32 params_addr) = (void (*)(int, int, u32))kernel_ram_base;……thekernel(0, arch_number, (u32) kernel_params_start);

注意,thekernel()函數(shù)調(diào)用應(yīng)該永遠(yuǎn)不返回的。如果這個(gè)調(diào)用返回,則說(shuō)明出錯(cuò)。


 

4. 關(guān)于串口終端

在 boot loader 程序的設(shè)計(jì)與實(shí)現(xiàn)中,沒(méi)有什么能夠比從串口終端正確地收到打印信息能更令人激動(dòng)了。此外,向串口終端打印信息也是一個(gè)非常重要而又有效的調(diào)試手段。但是,我們經(jīng)常會(huì)碰到串口終端顯示亂碼或根本沒(méi)有顯示的問(wèn)題。造成這個(gè)問(wèn)題主要有兩種原因:(1) boot loader 對(duì)串口的初始化設(shè)置不正確。(2) 運(yùn)行在 host 端的終端仿真程序?qū)Υ诘脑O(shè)置不正確,這包括:波特率、奇偶校驗(yàn)、數(shù)據(jù)位和停止位等方面的設(shè)置。

此外,有時(shí)也會(huì)碰到這樣的問(wèn)題,那就是:在 boot loader 的運(yùn)行過(guò)程中我們可以正確地向串口終端輸出信息,但當(dāng) boot loader 啟動(dòng)內(nèi)核后卻無(wú)法看到內(nèi)核的啟動(dòng)輸出信息。對(duì)這一問(wèn)題的原因可以從以下幾個(gè)方面來(lái)考慮:

(1) 首先請(qǐng)確認(rèn)你的內(nèi)核在編譯時(shí)配置了對(duì)串口終端的支持,并配置了正確的串口驅(qū)動(dòng)程序。

(2) 你的 boot loader 對(duì)串口的初始化設(shè)置可能會(huì)和內(nèi)核對(duì)串口的初始化設(shè)置不一致。此外,對(duì)于諸如 s3c44b0x 這樣的 cpu,cpu 時(shí)鐘頻率的設(shè)置也會(huì)影響串口,因此如果 boot loader 和內(nèi)核對(duì)其 cpu 時(shí)鐘頻率的設(shè)置不一致,也會(huì)使串口終端無(wú)法正確顯示信息。

(3) 最后,還要確認(rèn) boot loader 所用的內(nèi)核基地址必須和內(nèi)核映像在編譯時(shí)所用的運(yùn)行基地址一致,尤其是對(duì)于 uclinux 而言。假設(shè)你的內(nèi)核映像在編譯時(shí)用的基地址是 0xc0008000,但你的 boot loader 卻將它加載到 0xc0010000 處去執(zhí)行,那么內(nèi)核映像當(dāng)然不能正確地執(zhí)行了。

5. 結(jié)束語(yǔ)

boot loader 的設(shè)計(jì)與實(shí)現(xiàn)是一個(gè)非常復(fù)雜的過(guò)程。如果不能從串口收到那激動(dòng)人心的"uncompressing linux.................. done, booting the kernel……"內(nèi)核啟動(dòng)信息,恐怕誰(shuí)也不能說(shuō):"嗨,我的 boot loader 已經(jīng)成功地轉(zhuǎn)起來(lái)了!"。



 

COPYRIGHT(C) 2011 廈門(mén)永宏亞得機(jī)電科技有限公司版權(quán)所有(閩ICP備05025945號(hào)) ALL RIGHTS RESERVED?

電話: 0592-5190891 傳真: 0592-5190720 E-Mail: E-mail:yade8895@163.com
地址: 廈門(mén)市海滄區(qū)興港六里17號(hào)2607室 郵編:361009 聯(lián)系人:翟先生