uclinux 启动流程

14
uCLinux 启启启启 启启启 [email protected] http:// xuyuanchao.ie.cnu.edu.cn

Upload: zarifa

Post on 19-Jan-2016

173 views

Category:

Documents


0 download

DESCRIPTION

uCLinux 启动流程. 徐远超 [email protected] http://xuyuanchao.ie.cnu.edu.cn. blob. Src/blob/start.S. Blob 代码分析. 第一阶段的代码在 start.s 中定义,大小为 l KB ,它包括从系统上电后在 0x00000000 地址开始执行的部分。 这部分代码运行在 Flash 中,它包括对 S3C44B0 的一些寄存器的初始化和将 Blob 第二阶段代码从 Flash 拷贝到 SDRAM 中。 除去第一阶段的 lKB 代码,剩下的部分都是第二阶段的代码。 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: uCLinux 启动流程

uCLinux 启动流程徐远超

[email protected]

http://xuyuanchao.ie.cnu.edu.cn

Page 2: uCLinux 启动流程

blob Src/blob/start.S

Page 3: uCLinux 启动流程

Blob 代码分析 第一阶段的代码在 start.s 中定义,大小为 l KB ,它包括从

系统上电后在 0x00000000 地址开始执行的部分。 这部分代码运行在 Flash 中,它包括对 S3C44B0 的一些寄

存器的初始化和将 Blob 第二阶段代码从 Flash 拷贝到 SDRAM 中。

除去第一阶段的 lKB 代码,剩下的部分都是第二阶段的代码。 第二阶段的起始文件为 trampoline.s 被复制到 SDRAM 后,

就从第一阶段跳转到这个文件开始执行剩余部分代码。 第二阶段最大为 63KB ,单词 trampoline 词义为“蹦床”,

所以在这个程序中进行一些 BSS 段设置,堆栈的初始化等工作后,最后跳转到 main.c.

Page 4: uCLinux 启动流程

relocate: adr r0, _start

/* relocate the second stage loader */ add r2, r0, #(64 * 1024) /* blob maximum size is 64kB */ add r0, r0, #0x400 ldr r1, BLOB_START

/* r0 = source address * r1 = target address * r2 = source end address */ copy_loop: ldmia r0!, {r3-r10} stmia r1!, {r3-r10} cmp r0, r2 ble copy_loop

Page 5: uCLinux 启动流程

adr r0, real_vectors add r2, r0, #1024 ldr r1, =0x0c000000 add r1, r1, #0x08 vector_copy_loop: ldmia r0!, {r3-r10} stmia r1!, {r3-r10} cmp r0, r2 ble vector_copy_loop

/* turn off the LED. if it stays off it is an indication that * we didn't make it into the C code */ /* bl led_off */

/* blob is copied to ram, so jump to it */ ldr r0, BLOB_START mov pc, r0

Page 6: uCLinux 启动流程

Trampoline.S mrs r0, cpsr bic r0, r0, #0x80 msr cpsr, r0

/* jump to C code */ bl main /* if main ever returns we just call it again */ b _trampoline

Page 7: uCLinux 启动流程

Main.c /* wait 10 seconds before starting autoboot */ SerialOutputString("Autoboot in progress, press any key to stop "); for(i = 0; i < blob_status.boot_delay; i++) { serial_write('.');

retval = SerialInputBlock(commandline, 1, 1); if(retval > 0) break; }

/* no key was pressed, so proceed booting the kernel */ if(retval == 0) { commandline[0] = '\0'; parse_command("boot"); }

Page 8: uCLinux 启动流程

Linux.c static int boot_linux(int argc, char *argv[]) { void (*theKernel)(int zero, int arch) = (void (*)(int, int))KERNEL_RAM_BASE;

clif(); setup_start_tag(); setup_memory_tags(); setup_commandline_tag(argc, argv); setup_initrd_tag(); setup_ramdisk_tag(); setup_end_tag();

/* we assume that the kernel is in place */ SerialOutputString("\nStarting kernel ...\n\n"); serial_flush_output();

/* disable subsystems that want to be disabled before kernel boot */ exit_subsystems();

/* start kernel */ theKernel(0, ARCH_NUMBER);

SerialOutputString("Hey, the kernel returned! This should not happen.\n");

return 0; }

Page 9: uCLinux 启动流程

设置内核的启动参数 Linux 2.4.x 以后的内核都期望以标记列表 (tagged l

ist) 的形式来传递启动参数 启动参数标记列表以标记 ATAG_CORE 开始,以

标记 ATAG_NONE 结束 每个标记由标识被传递参数的 tag_header 结构以

及随后的参数值数据结构来组成 在嵌入式 Linux 系统中,通常需要由 Boot Loader

设置的常见启动参数有: ATAG_CORE 、ATAG_MEM 、 ATAG_CMDLINE 、 ATAG_RAMDISK 、 ATAG_INITRD 等 .

Page 10: uCLinux 启动流程

直接跳转到内核的第一条指令处 在跳转时,下列条件要满足

• 1 . CPU 寄存器的设置 R0 = 0 ; @R1 =机器类型 ID ; @R2 =启动参数标记列表在

RAM 中起始基地址• 2 . CPU 模式

必须禁止中断( IRQs 和 FIQs ); CPU 必须 SVC 模式;

• 3 . Cache 和 MMU 的设置 MMU 必须关闭; 指令 Cache 可以打开也可以关闭; 数据 Cache 必须关闭 .

Page 11: uCLinux 启动流程

内核解压缩

为了节省 ROM 空间,内核都是压缩过的,因此要有专门的解压缩程序解压缩内核。真正完成这个功能的函数是 decompress_kernel() ,该函数在文件 misc.c 中定义,其中misc.c 在目录 uClinux-2.4.x\arch\armnommu\boot\compressed 中

Page 12: uCLinux 启动流程

解压后,跳转到解压后的地址处执行

该函数完成的功能包括处理器结构的初始化、中断的初始化、定时器的初始化、进程相关的初始化以及内存初始化等初始化工作完成内核初始化;最后内核创建一个 init 线程,在该线程中调用 init 进程,完成系统的启动。

Page 13: uCLinux 启动流程

rest_init

static void rest_init(void){

kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);

// 用 kernel_thread 建立了一个 init 进程 ,执行的是 main.c 中的 init 函数unlock_kernel(); // 内核解锁,不受保护current->need_resched = 1; // 该线程的标志位 need_resched 置位为 1

cpu_idle(); // 实现了进程 init 的被调度 , 从而函数 init() 被执行。

}

Page 14: uCLinux 启动流程

Init 函数 首先调用 do_basic_setup() 来完

成外部设备以及驱动程的初始化,然后在函数调用完成后, init() 会调用函数 prepare_namespace()来登录 root 文件系统,并加载 RAMDISK 。接下来 init() 会调用函数 free_initmem() 来释放内核初始化函数所用的系统内存,并且打开 /dev/console 设备重新定向控制台,让系统调用 execve 来执行 shell 程序 init 。