fiasco内核分析——启动

前提1:以arm64架构为例进行fiasco内核分析

前提2:编译生成arm64架构任意entry的镜像文件后,在编译路径下有个auto文件夹,其中就包含通过perl预处理后生成的内核源文件;通过rm *.ready命令删除临时文件;

通过sed -i '/#line/d' *.ccsed -i '/#line/d' *.h命令去掉源文件中的临时注释行;就得到一个相对标准的C++实现的fiasco内核源代码。

前提3下文中提到的源文件名皆以auto目录下的文件名为准。

 

首先找到kernel.arm64.ld链接文件,部分字段如下:

virt_address       = 0xffff000040000000;

 

phys_offset        = virt_address - kernel_load_addr;

 

OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64",

              "elf64-littleaarch64")

 

OUTPUT_ARCH(aarch64)

 

ENTRY(_start)

 

SECTIONS {

……

可以看到,程序入口为_start”。

bootstrap-arm-64.cc文件中有段嵌入式汇编代码,指示_start的功能就是跳转到bootstrap_main执行。

asm

(

……

".global _start                        \n"

"_start:                               \n"

"     ldr x9, =_stack                  \n"

"     mov sp, x9                       \n"

"     bl bootstrap_main         \n"

……);

函数bootstrap_mainbootstrap.cc文件中。

在函数bootstrap_main中,会调用paging初始化函数,内容包括:刷EL2TLB、设置SCRmonitor mode、配置gic、从EL3跳转到EL2等。最后调用全局变量bs_info.entry(),跳转到内核的入口,完成bootstrap功能。

那么内核的入口在哪里呢?或者说bs_info结构体在哪里初始化的呢?注意到其定义方式:

Bootstrap_info FIASCO_BOOT_PAGING_INFO bs_info;

#define FIASCO_BOOT_PAGING_INFO \

  __attribute__((section(".bootstrap.info"), used))

bs_info定义到了“.bootstrap.info”内存段中。全局搜索可以发现在编译目录下有个链接文件kernel.arm.lds中包含如下字段:

SECTIONS {

  /DISCARD/ : {

  *(.exitcall.exit)

                *(.bootstrap.dropped*)

       }

  . = kernel_load_addr + 0x1000;

  .text : {

    QUAD(_start_kernel)

    QUAD(my_kernel_info_page)

    KEEP(*(.bootstrap.info))

    ASSERT (ABSOLUTE(.) == end_of_bootstrap_info, "invalid size of bootstrap.info");

    . = ABSOLUTE(start_of_loader);

    *(.bootstrap.text)

  } :bstrap

……

对的,就是这个_start_kernel就是内核入口(我们这里只讨论流程,不讨论具体实现细节)。

搜索源码目录,发现_start_kernel定义在crt0.S中(越来越像linux了):

.section .text.init,#alloc,#execinstr

.type start,#function

ENTRY(_start_kernel)

ENTRY(start)

        ldr     x9, =_stack;

        mov     sp, x9

        bl      __main

 

     /* never returns */

 

.section ".init.data"

.p2align 4

.globl _sstack

_sstack:

        .space  4096

.globl _stack

.type _stack,#object

_stack:

 

发现这其实也是个跳转,真正入口来了——“__main”在__main.cc中。

其中的核心函数kernel_mainmain.cc中,下面具体分析kernel_main函数。

 

kernel_main

打印版本号信息;

创建kernel线程;

创建kernel_task

调用kernel线程的bind函数对线程和task进行绑定;

Tlb_flush

切换到kernelstack并调用“call_bootstrap”启动kernel线程。

 

注意到,kernel_thread.hclass的定义:

class Kernel_thread : public Thread_object

{

private:

  void free_initcall_section();

  void bootstrap() asm ("call_bootstrap") FIASCO_FASTCALL;

  void bootstrap_arch();

……

所以,转到kernel_thread.cc中来看Kernel_thread::bootstrap()的实现,

Kernel_thread::bootstrap()

初始化每个cpu的数据;

设置当前cpu号;

设置自身ready

初始化timer0

将当前线程加入调度链表;

让当前task运行;

boot CPU上初始化系统时钟;

使能TLB

调用bootstrap_arch函数,并在其中调用boot_app_cpus函数启动从核;

boot CPU上使能系统时钟;

使能watchdog

调用run函数,进入idle线程。

 

至此,fiasco的启动流程分析完毕,系统进入idle线程,通过schedule进行线程调度。

总结一下,整个启动调用关系为:

_start——》bootstrap_main——》_start_kernel——》__main——》kernel_main

——》Kernel_thread::bootstrap

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值