比如,我們用這樣一個命令行參數字符串“console=ttyS0,115200n8”來通知內核以ttyS0 作為控制臺,且串口采用 “115200bps、無奇偶校驗、8位數據位”這樣的設置。下面是一段設置調用內核命令行參數字符串的示例代碼:
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);
請注意在上述代碼中,設置 tag_header 的大小時,必須包括字符串的終止符‘\0’,此外還要將字節數向上圓整4個字節,因為 tag_header 結構中的size 成員表示的是字數。
下面是設置 ATAG_INITRD 的示例代碼,它告訴內核在 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);
下面是設置 ATAG_RAMDISK 的示例代碼,它告訴內核解壓后的 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; /* 請注意,單位是KB */
params->u.ramdisk.flags = 1; /* automatically load ramdisk */
params = tag_next(params);
最后,設置 ATAG_NONE 標記,結束整個啟動參數列表:
static void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
3.2.5 調用內核
Boot Loader 調用 Linux 內核的方法是直接跳轉到內核的第一條指令處,
也即直接跳轉到 MEM_START+0x8000 地址處。在跳轉時,下列條件要滿足:
CPU 寄存器的設置:
R0=0;
R1=機器類型 ID;關于 Machine Type Number,可以參見 linux/arch/arm/tools/mach-types。
R2=啟動參數標記列表在 RAM 中起始基地址;
CPU 模式:
必須禁止中斷(IRQs和FIQs);
CPU 必須 SVC 模式;
Cache 和 MMU 的設置:
MMU 必須關閉;
指令 Cache 可以打開也可以關閉;
數據 Cache 必須關閉;
如果用 C 語言,可以像下列示例代碼這樣來調用內核:
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()函數調用應該永遠不返回的。如果這個調用返回,則說明出錯。
四. 關于串口終端
在 boot loader 程序的設計與實現中,沒有什么能夠比從串口終端正確地收到打印信息能更令人激動了。此外,向串口終端打印信息也是一個非常重要而又有效的調試手段。但是,我們經常會碰到串口終端顯示亂碼或根本沒有顯示的問題。造成這個問題主要有兩種原因:
boot loader 對串口的初始化設置不正確。
運行在 host 端的終端仿真程序對串口的設置不正確,這包括:波特率、奇偶校驗、數據位和停止位等方面的設置。
此外,有時也會碰到這樣的問題,那就是:在 boot loader 的運行過程中我們可以正確地向串口終端輸出信息,但當 boot loader 啟動內核后卻無法看到內核的啟動輸出信息。對這一問題的原因可以從以下幾個方面來考慮:
首先請確認你的內核在編譯時配置了對串口終端的支持,并配置了正確的串口驅動程序。
你的 boot loader 對串口的初始化設置可能會和內核對串口的初始化設置不一致。此外,對于諸如 s3c44b0x 這樣的 CPU,CPU 時鐘頻率的設置也會影響串口,因此如果boot loader 和內核對其 CPU 時鐘頻率的設置不一致,也會使串口終端無法正確顯示信息。
最后,還要確認 boot loader 所用的內核基地址必須和內核映像在編譯時所用的運行基地址一致,尤其是對于 uClinux 而言。假設你的內核映像在編譯時用的基地址是0xc0008000,但你的 boot loader 卻將它加載到 0xc0010000 處去執行,那么內核映像當然不能正確地執行了。
五. 結束語
Boot Loader 的設計與實現是一個非常復雜的過程。
評論
查看更多