fiasco内核分析——内核时钟

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gaojy19881225/article/details/80909920

如上篇分析,在fiasco系统启动的最后阶段——Kernel_thread::bootstrap中,会调用bootstrap_arch函数启动从核,同时启动每个核上的timer定时器。下面具体分析。

bootstrap_arch——》boot_app_cpus——》Platform_control::boot_ap_cpus_tramp_mp_entry

注意到定义:

extern char _tramp_mp_entry[];

全局搜索,发现_tramp_mp_entry只有在汇编文件中有定义——tramp-mp.S,为一个汇编函数变量:

.global _tramp_mp_entry

_tramp_mp_entry:

        msr     DAIFSet, #0xf

        bsp_early_init x0, x1

        mrs     x17, CurrentEL

        lsr     x17, x17, #2

        cmp     x17, #3 // running at EL3

        b.ne    .Lnot_el3

……

.Lnot_el3:

        cmp     x17, #2

#ifndef CONFIG_CPU_VIRT

        b.ne  2f

        mov     x6, #((1 << 29) | (1<< 31)) // RW + HCD

        msr     HCR_EL2, x6

        movz    x17, #((0xf << 6) | 5) // DAIF + EL1 / SPSEL

        msr     SPSR_EL2, x17

……

ldr x0, 1f

        br x0

        .align 3

1:

        .8byte _tramp_mp_virt

……

        // we run paged now

_tramp_mp_virt:

        // spinlock on cpu-init

        adr     x0, _tramp_mp_spinlock

1:      ldr     x1, [x0]

        cbz     x1, 2f

        b       1b

……

        ldr     x9, 3f

        br      x9

.align 4

3:

        .8byte BOOT_AP_CPU

可以看到,在_tramp_mp_entry函数末尾,调用了BOOT_AP_CPU函数。

在文件main.cc中有这样的定义:

int boot_ap_cpu() __asm__("BOOT_AP_CPU");

可见,绕来绕去,最终调用的是main.cc中的boot_ap_cpu()函数。

函数boot_ap_cpu()中会进行一系列初始化,其中就包括时钟初始化——Timer::init(_cpu),最后调用call_ap_bootstrap启动从核。

下面我们来看一下时钟初始化函数——Timer::init(Cpu_number cpu)

1. 首先判断cpu是否有通用定时器,如果没有,panic

2. 在启动cpu上获取系统时钟频率,并设置定时器中断的_interval

一步步跟,可以发现在class Timer中有个定义:

typedef Generic_timer::Gtimer Gtimer;

所以是用到了Generic_timer::Gtimer中的frequency函数,最终会调用嵌入汇编,通过msr指令来获取系统时钟:

static Unsigned32 frequency()

    { Unsigned32 v; asm volatile ("mrs %0, CNTFRQ_EL0": "=r" (v)); return v; }

设置_interval

_interval = (Unsigned64)_freq0 * Config::Scheduler_granularity / 1000000;

其中Config::Scheduler_granularity 在没设置oneshot模式下为1000,所以定时器中断时间为1ms(即HZ数为1000),否则为1us

3. 设置定时器访问权限

static void setup_timer_access()

{

      // CNTKCTL: allow access to virtual and physical counter from EL0

      asm volatile("msr CNTKCTL_EL1, %0" : : "r"(0x3));

      // CNTHCTL: forbid access to physical timer from EL0 and EL1

      asm volatile("msr CNTHCTL_EL2, %0" : : "r"(0x0));

}


4. 等待timer运行。

至此,fiasco的系统时钟初始化完毕。

猜你喜欢

转载自blog.csdn.net/gaojy19881225/article/details/80909920