QNX源码下三大主分支,也是组成QNX系统的三大模块:Initial program loader(IPL)、Startup、Flash Filesystem
1、IPL介绍
IPL是一段初始化启动程序类似于uboot,在启动QNX时也可以用uboot替代,不过IPL更加简洁,启动时间更快。IPL的主要职责就是进行最小的硬件配置以启动Startup程序,从而启动microkernel,至少包括以下工作:
①从重置向量开始执行
②配置内存控制器
③配置时钟
④设置一个栈,以允许IPL库执行操作系统的验证和设置(download, scan, set up, and jump to the OS image)
根据bsp_working_dir/src/hardware/ipl/boards/mx6q_sabresmart/mx6q_sabresmart.lnk的链接来看
-
TARGET(elf32-littlearm)
-
OUTPUT_FORMAT(elf32-littlearm)
-
ENTRY(_start)
-
MEMORY
-
{
-
stack : ORIGIN =
0x90C000, LENGTH =
0x1000
-
rom : ORIGIN =
0x907000, LENGTH =
0x6000
-
}
-
-
SECTIONS
-
{
-
.text : {
-
image_header.o (.text.imageheader)
-
*(.text)
-
*(.note.gnu.build-id)
-
*(.rodata*)
-
} > rom
-
-
. = ALIGN(
4);
-
_etext = .;
-
-
.
data : { *(.
data)
-
*(.sdata)
-
} > rom
-
-
. = ALIGN(
4);
-
_ecopy = .;
-
-
.bss : {
-
*(.bss)
-
*(.sbss)
-
} > rom
-
}
-
_start:
-
/*
-
* 将CPU设置为SVC32管理模式
-
*/
-
mrs r0, cpsr
-
bic r0, r0,
#0x1f
-
orr r0, r0,
#0xd3
-
msr cpsr,r0
-
-
/*
-
* 禁止 L1 I/D and TLBs
-
*/
-
mov r0,
#0 @ set up for MCR
-
mcr p15,
0, r0, c8, c7,
0 @ invalidate TLBs
-
mcr p15,
0, r0, c7, c5,
0 @ invalidate icache
-
-
/*
-
* 禁止 MMU and Caches
-
*/
-
mrc p15,
0, r0, c1, c0,
0
-
bic r0, r0,
#0x00002000 @ clear bits 13 (--V-)
-
bic r0, r0,
#0x00000007 @ clear bits 2:0 (-CAM)
-
orr r0, r0,
#0x00000002 @ set bit 1 (--A-) Align
-
orr r0, r0,
#0x00000800 @ set bit 12 (Z---) BTB
-
mcr p15,
0, r0, c1, c0,
0
-
-
mrc p15,
0, ip, c1, c0,
0
-
orr ip, ip,
#(1 << 12) // enable I Cache
-
mcr p15,
0, ip, c1, c0,
0
-
dsb
-
isb
-
mov r0, r0
-
mov r0, r0
-
mov r0, r0
-
mov r0, r0
-
-
inv_dcache
/*禁止D-Cache*/
-
init_l2cc
/*禁止I-Cache*/
-
-
/* Setup the Stack */
-
ldr sp, =
0x90C000
-
-
bl main
/*跳入C语言代码*/
-
int main()
-
{
-
unsigned image = QNX_LOAD_ADDR;
//0x18000000
-
char c =
'M';
/* default: load ifs from SD card */
-
-
/* Allow access to the AIPS registers */
-
init_aips();
-
-
/* Initialise the system clocks */
-
init_clocks();
-
-
init_pinmux();
//引脚配置,这里包括串口、装置image的SD
-
-
/* Init serial interface */
-
/* 115200bps, 80MHz clk, divisor (RFDIV 1-7) 2 */
-
init_sermx6(MX6X_UART1_BASE,
115200,
80000000,
2);
//初始化串口
-
-
ser_putstr(
"\nWelcome to QNX Neutrino Initial Program Loader for Freescale i.MX6Q Sabre-Smart (ARM Cortex-A9 MPCore)\n");
-
-
while (
1) {
-
if (!c) {
-
ser_putstr(
"Command:\n");
-
ser_putstr(
"Press 'D' for serial download, using the 'sendnto' utility\n");
-
ser_putstr(
"Press 'M' for SDMMC download, IFS filename MUST be 'QNX-IFS'.\n");
-
c = ser_getchar();
-
}
-
switch (c) {
-
case
'D':
-
case
'd':
-
ser_putstr(
"send image now...\n");
-
if (image_download_ser(image)) {
-
ser_putstr(
"download failed...\n");
-
c =
0;
-
}
-
else
-
ser_putstr(
"download OK...\n");
-
break;
-
case
'M':
-
case
'm':
-
ser_putstr(
"SDMMC download...\n");
-
if (sdmmc_load_file(image,
"QNX-IFS") ==
0) {
//加载image(QNX-IFS),所以需要把编译的好的image 改名为QNX-IFS
-
ser_putstr(
"load image done.\n");
-
/* Proceed to image scan */
-
}
-
else {
-
ser_putstr(
"Load image failed.\n");
-
c =
0;
-
}
-
break;
-
default:
-
ser_putstr(
"Unknown command.\n");
-
c =
0;
-
}
-
if (!c)
continue;
-
-
-
image = image_scan_2(image, image +
0x200,
1);
//关键函数1
-
-
if (image !=
0xffffffff) {
-
ser_putstr(
"Found image @ 0x");
-
ser_puthex(image);
-
ser_putstr(
"\n");
-
image_setup(image);
//关键函数2
-
-
ser_putstr(
"Jumping to startup @ 0x");
-
ser_puthex(startup_hdr.startup_vaddr);
-
ser_putstr(
"\n\n");
-
image_start(image);
//关键函数3
-
-
/* Never reach here */
-
return
0;
-
}
-
ser_putstr(
"Image_scan failed...\n");
-
}
-
-
return
0;
-
}
-
struct startup_header {
-
unsigned
long signature;
/* 头标志
0x00FF7EEB
*/
-
unsigned
short version;
/*
mkifs版本号
*/
-
unsigned
char flags1;
/*IS Misc flags, see below*/
-
unsigned
char flags2;
/* No flags defined yet*/
-
unsigned
short header_size;
/* sizeof(struct startup_header) */
-
unsigned
short machine;
/* 机器型号 sys/elf.h*/
-
unsigned
long startup_vaddr;
/* 在IPL执行完后的跳转地址,也就是startup开始执行的地址*/
-
unsigned
long paddr_bias;
/*S Value to add to physical address*/
-
/* to get a value to put into a*/
-
/* pointer and indirected through*/
-
unsigned
long image_paddr;
/* image的物理地址*/
-
unsigned
long ram_paddr;
/* 将image复制到RAM中的物理地址*/
-
unsigned
long ram_size;
/* image占用RAM空间大小*/
-
-
unsigned
long startup_size;
/* startup大小*/
-
unsigned
long stored_size;
/* 整个QNF-IFS大小,包括iamge 和headr*/
-
unsigned
long imagefs_paddr;
/* 将IPL设置为映像文件系统的物理地址*/
-
unsigned
long imagefs_size;
/* 未压缩映像文件系统的大小*/
-
unsigned
short preboot_size;
/*I Size of loaded before header*/
-
unsigned
short zero0;
/* Zeros */
-
unsigned
long zero[
3];
/* Zeros */
-
unsigned
long info[
48];
/*IS Array of startup_info* structures*/
-
};
从图上可以很清楚看到各参数的作用,总体来说就IPL就需要这几个步骤
-
checksum (image_paddr, startup_size)
-
checksum (image_paddr + startup_size, stored_size - startup_size)
-
copy (image_paddr, ram_paddr, startup_size)
-
jump (startup_vaddr)
上面三个关键函数,就是完成这几个步骤的:
关键函数①:
-
unsigned long image_scan_2 (unsigned long start, unsigned long end, int docksum)
-
{
-
struct startup_header *hdr;
-
-
/*
-
* image starts on word boundary
-
* We need this scan because it could have 8 raw bytes in front of imagefs
-
* depending on how the IFS is programmed
-
*/
-
for (; start < end; start +=
4) {
-
hdr = (struct startup_header *)(start);
-
-
/* No endian issues here since stored "naturally" */
-
if (hdr->signature == STARTUP_HDR_SIGNATURE)
//搜寻头标志位,这个一个startup_header开始的标志位
-
break;
-
}
-
-
if (start >= end)
-
return (
-1L);
-
-
copy ((
unsigned
long)(&startup_hdr), start,
sizeof(startup_hdr));
// startup_hdr是一个由startup_header定义的全局变量
-
-
/* now we got the image signature */
-
if (docksum) {
-
#ifdef __ARM__ //检测 startup
-
if (checksum_2(start, startup_hdr.startup_size) !=
0) {
-
#else
-
if (checksum(start, startup_hdr.startup_size) !=
0) {
-
#endif
-
ser_putstr(
"startup checksum error\n");
-
return (
-1L);
-
}
-
-
#ifdef __ARM__ //检测 image
-
if (checksum_2(start + startup_hdr.startup_size, startup_hdr.stored_size - startup_hdr.startup_size) !=
0) {
-
#else
-
if (checksum(start + startup_hdr.startup_size, startup_hdr.stored_size - startup_hdr.startup_size) !=
0) {
-
#endif
-
ser_putstr(
"imagefs checksum error\n");
-
return (
-1L);
-
}
-
}
-
-
return (start);
-
}
-
int image_setup (
unsigned
long addr) {
-
unsigned
long ram_addr;
-
-
//
-
// Copy the data from the address into our structure in memory
-
//
-
-
copy ((
unsigned
long)(&startup_hdr), addr,
sizeof(startup_hdr));
-
-
//
-
// get ram_addr and patch startup with the images physical
-
// location. Startup will handle the rest ...
-
//
-
-
ram_addr = startup_hdr.ram_paddr + startup_hdr.paddr_bias;
-
startup_hdr.imagefs_paddr = addr + startup_hdr.startup_size - startup_hdr.paddr_bias;
-
-
//
-
// Copy startup to ram_addr.
-
//
-
-
copy(ram_addr,(
unsigned
long)(&startup_hdr),
sizeof(startup_hdr));
//拷贝startup_header结构体信息
-
-
copy ((ram_addr+
sizeof(startup_hdr)),(addr+
sizeof(startup_hdr)), (startup_hdr.startup_size -
sizeof(startup_hdr)));
//拷贝startup本身
-
-
//
-
// All set now for image_start
-
//
-
-
return(
0);
-
}
-
int image_start (
unsigned
long addr) {
-
-
copy ((
unsigned
long)(&startup_hdr), addr,
sizeof(startup_hdr));
-
-
//
-
// Options here include custom jump functions,
-
// cast as a function call? use the longjmp call
-
//
-
-
jump (startup_hdr.startup_vaddr);
//跳转到startup开始执行
-
-
return(
-1);
-
}
IPL这段精简的代码主要流程如下
①初始化硬件 (汇编代码_start.S)
②将image下载到RAM (sdmmc_load_file())
③定位 OS image (image_scan_2())
④拷贝startup程序 (image_setup())
⑤跳转到加载好的image执行 (image_start())