L4微内核分析(mips64架构)

pistachio-0.4/kernel/src/glue/v4-mips64/init.cc文件中的startup_system()函数分析:

 

extern "C" void SECTION(".init") startup_system(word_t a0, word_t a1, word_t a2, word_t a3) 
{
    init_cpu();    初始化CPU,配置
    init_cpu_cache();
    cache_t::init_cpu();  该函数实现在kernel/src/glue/v4-mips64/init.cc
      ①、将Config Register(CP0 register 16,Select 0)寄存器的值存入临时temp变量
      ②、清空该寄存器的K0(3bit)字段,该字段用来控制Kseg0 Cache attributes
      ③、设置K0字段为3,表示Cache able,noncoherent,write-back,write alloc特性
      ④、将temp值重新保存到Config Register(CP0 register 16,Select 0)寄存器
      ⑤、初始化dcache和icache,两个cache开始地址KSEG0(0xffffffff80000000),大小均为(16*1024)。
        该过程从KSEG0开始一直到结束,将TagLo和TagHi寄存器的值写入指定索引cache块的tag区,具体参考
        https://blog.csdn.net/xiaoseha/article/details/50981817 init_platform(a0); 该函数实现在pistachio-0.4/kernel/src/platform/u4600/plat.cc中
     ①、plat_cpu_freq[0] = 100000000ul; 向cpu频率数组写入相应频率
     ②、plat_bus_freq[0] = 33300000ul;  向bus频率数组写入bus频率 init_console();
     kdb_consoles[kdb_current_console].init ();该类实现在kernel/kdb/platform/u4600/serial.cc中
                包括串口初始化(init_serial)、串口输出(putc_serial),串口输入(getc_serial) init_hello();  该函数在pistachio-0.4/kernel/src/api/v4/kernelinterface.cc中实现
     printf ("\n" TXT_BRIGHT TXT_FG_YELLOW "%s" TXT_NORMAL "\n",kernel_version_string); init_arch();   该函数是重点函数,在pistachio-0.4/kernel/src/glue/v4-mips64/init.cc中实现
     ①、init_tlb();  初始化tlb,在pistachio-0.4/kernel/src/glue/v4-mips64/tlb.cc中实现
       a)、清PageMask Register(CP0 Register 5,select 0)寄存器
       b)、将Index Register(CP0 Register 0,select 0)寄存器的值存储到Wired Register(CP0 Register 6,select 0)
       c)、分48次将递增索引存储到Index Register和EntryHi Register中,然后将Index Register的内容填充到
         EntryLo0和EntryLo1寄存器中。本过程使用for循环执行48次。
       d)、将Index Register寄存器中的值存储到EntryHi Register寄存器中
     ②、get_interrupt_ctrl()->init_arch();  初始化IRQ中断(通用初始化函数)
       void SECTION (".init") intctrl_t::init_arch(void) 在kernel/src/glue/v4-mips64/intctrl.cc实现
         a)、mips_cpu::cli(); 该函数在kernel/include/arch/mips64/mips_cpu.h实现
           将Status寄存器的值存储到Random寄存器,Random的值与1进行或操作,再将Random的值与1进行异或操作,最后
           把Random的值存储到Status寄存器中。(该操作设定Status寄存器的IE位为1,使能全局中断)
           然后将Index寄存器整体左移3位。
         b)、复制MIPS的异常向量表到KSEG0 0xFFFFFFFF80000000。异常向量表位于kernel/src/glue/v4-mips64/traps.S
          memcpy((void *)(KSEG0), &__mips64_tlb_refill, 0x80);
          memcpy((void *)(KSEG0 + 0x080), &__mips64_xtlb_refill, 0x80);
            memcpy((void *)(KSEG0 + 0x100), &__mips64_cache_error, 0x80);
            memcpy((void *)(KSEG0 + 0x180), &__mips64_interrupt, 0x80);
          memcpy((void *)(KSEG0 + 0x200), &__mips64_extra_vector, 0x80);
         c)、cache_t::flush_cache_all(); 该函数在kernel/include/platform/u4600/cache.h中实现
          blast_dcache16(); blast_icache16();上述两个函数在kernel/include/platform/u4600/cache.h实现
         d)、将MIPS64架构的32个异常复制到异常处理数组,指向同一个处理函数
          for (i=0; i<32; i++)
              exception_handlers[i] = (word_t)&_mips64_exception;
         e)、将MIPS64架构的8个中断处理函数复制到中断处理数组中,指向同一个中断处理函数
          for (i=0; i<8; i++)
              interrupt_handlers[i] = (word_t)spurious_interrupt;
         f)、setup_exception_vectors(); 设置异常向量表,在kernel/src/glue/v4-mips64/intctrl.cc中实现
           此处未加详细说明,会在后期文档进行分析。
    ③、get_interrupt_ctrl()->init_cpu();配置中断(本CPU专属中断)kernel/src/glue/v4-mips64/intctrl.cc实现
      a)、mips_cpu::clear_cp0_status(ST_IM);该函数实现在kernel/include/arch/mips64/mips_cpu.h
          #define ST_IM  (0xff<<8)
          res = read_32bit_cp0_register(status); 在kernel/include/arch/mips64/mipsregs.h实现
          res &= ~clear;
          write_32bit_cp0_register(status, res);  在kernel/include/arch/mips64/mipsregs.h实现
      b)、get_idle_tcb()->arch.int_mask = 0;      int_mask位于idle tcb中,每次CPU中断标识位  
      c)、mips_cpu::clear_cp0_status(ST_BEV);
          #define ST_BEV      (1<<22) 
    ④、get_asid_cache()->init();  初始化所有的ASID cache为无效,在kernel/include/asid.h中实现 
    ⑤、get_asid_cache()->set_valid(0, CONFIG_MAX_NUM_ASIDS-1);  设置ASID cache为有效 
    ⑥、init_bootmem();使用初始化内存初始化内核调试器,并在内核信息页中注册内存,在kernel/src/glue/v4-mips64/init.cc
      a)、设置开始启动内存地址,并转换为虚拟地址
        addr_t start_bootmem = (addr_t)(_bootstack_top);  _bootstack_top在链接脚本中定义
        addr_t start_bootmem_phys = virt_to_phys(start_bootmem);
          return (addr_t) ((word_t) addr - AS_KSEG_START);
          AS_KSEG_START在kernel/include/arch/mips64/page.h中定义,定义如下:
          #define AS_KSEG_START  AS_CKSEG0_START
          #define AS_CKSEG0_START  (0xFFFFFFFF80000000)
      b)、对start_bootmem地址进行判定,该地址应大于sigma0、sigma1、root_server内存区域的最高地址
        if ((word_t)start_bootmem_phys < (word_t)get_kip()->sigma0.mem_region.high)
          start_bootmem_phys = get_kip()->sigma0.mem_region.high;
        if ((word_t)start_bootmem_phys < (word_t)get_kip()->sigma1.mem_region.high)
          start_bootmem_phys = get_kip()->sigma1.mem_region.high;
        if ((word_t)start_bootmem_phys < (word_t)get_kip()->root_server.mem_region.high)
          start_bootmem_phys = get_kip()->root_server.mem_region.high;
        上述中sigma0、sigma1、root_server的kip结构体在kernel/src/api/v4/kernelinterface.cc中定义,按照初始值
        来看上述各内存最高地址均为0????????kernel_interface_page_t kip UNIT("kip")={...}
      c)、将最终的start_bootmem_phys物理地址转换为虚拟地址
        start_bootmem = phys_to_virt(start_bootmem_phys);
          return (addr_t) ((word_t) addr +  AS_KSEG_START);
      d)、设置内存结束地址,
        #define BOOTMEM_PAGES (CONFIG_BOOTMEM_PAGES)
        #define MIPS64_PAGE_BITS         12
        word_t bootmem_size = BOOTMEM_PAGES<<MIPS64_PAGE_BITS;
        addr_t end_bootmem = (addr_t)((word_t)start_bootmem + bootmem_size);
        addr_t end_bootmem_phys = (addr_t)((word_t)start_bootmem_phys + bootmem_size);
      e)、初始化内核内存
        kmem.init (start_bootmem, end_bootmem);具体函数实现在kernel/src/generic/kmemory.cc中
          SECTION(SEC_INIT) void kmem_t::init(void * start, void * end)
            初始化成员:kmem_free_list = NULL;free_chunks = 0;
            释放空间:free(start, (word_t)end - (word_t)start);
      f)、定义并向内核插入用户虚拟地址空间
        get_kip ()->memory_info.insert( memdesc_t::conventional, true,
        (addr_t)0, (addr_t)(1ULL<<CONFIG_MIPS64_ADDRESS_BITS));
          bool insert (memdesc_t::type_e type, bool virt, addr_t low, addr_t high)
            return insert (type, 0, virt, low, high);
      g)、向内核接口页注册剩余空间,
        get_kip ()->memory_info.insert( memdesc_t::conventional, false,
          (addr_t)MIPS64_PAGE_SIZE, addr_align (get_kip()->main_mem.high, KB(4)));
        get_kip ()->memory_info.insert( memdesc_t::reserved, false,
          addr_align_up (get_kip()->main_mem.high, KB(4)), (addr_t)~0UL);
        get_kip ()->memory_info.insert (memdesc_t::reserved, false,
          addr_align (start_text_phys, KB(4)),
          addr_align_up (end_text_phys, KB (4)));
        get_kip ()->memory_info.insert (memdesc_t::reserved, false,
          addr_align (start_bootmem_phys, KB(4)),
          addr_align_up (end_bootmem_phys, KB (4)));

      h)、预留一部分空间作为异常向量表区域
        get_kip ()->memory_info.insert( memdesc_t::reserved, false,
          (addr_t)0, (addr_t)MIPS64_PAGE_SIZE);
    ⑦、get_kip()->init();  初始化内核接口页
      void SECTION(".init") kernel_interface_page_t::init()在kernel/src/api/v4/kernelinterface.cc定义
        #define SET_KIP_SYSCALL(x) this->x##_syscall = KIP_SYSCALL(user_##x)
        SET_KIP_SYSCALL(space_control);
        SET_KIP_SYSCALL(thread_control);
         SET_KIP_SYSCALL(processor_control);
          SET_KIP_SYSCALL(memory_control);
          SET_KIP_SYSCALL(ipc);                                                                                                                      
          SET_KIP_SYSCALL(lipc);
          SET_KIP_SYSCALL(unmap);
          SET_KIP_SYSCALL(exchange_registers);
          SET_KIP_SYSCALL(system_clock);
         SET_KIP_SYSCALL(thread_switch);
         SET_KIP_SYSCALL(schedule);

        #define SET_KIP_ARCH_SYSCALL(n) this->arch_syscall##n = ARCH_SYSCALL##n
        SET_KIP_ARCH_SYSCALL (0);
          SET_KIP_ARCH_SYSCALL (1);
          SET_KIP_ARCH_SYSCALL (2);
          SET_KIP_ARCH_SYSCALL (3);
    ⑧、init_pageing();    初始化页表
      init_kernel_space();  创建并初始化内核空间
        kernel_space = allocate_space();  分配内存空间
        kernel_space->get_asid()->init();  初始化内存空间
        kernel_space->init_kernel_mappings(); 映射内存空间
        dummy_tcb = (tcb_t *) kmem.alloc(kmem_tcb, ALPHA_PAGE_SIZE);分配假的tcb结构体
    ⑨、init_mdb ();      初始化映射基址(Initialize mapping database structures)
      a)、mdb_buflist_init ();
      b)、dual = mdb_create_dual (NULL, mdb_create_roots (mapnode_t::size_max));完整地址框架表
      c)、使sigma0属于整个地址空间
        sigma0_mapnode = &__sigma0_mapnode;
        sigma0_mapnode->set_backlink ((mapnode_t *) NULL, (pgent_t *) NULL);
        sigma0_mapnode->set_space ((space_t *) 0);
        sigma0_mapnode->set_depth (0);
        sigma0_mapnode->set_next (dual);
      d)、功能:Sanity checking of pgshift arrays.
          for (i = (pgent_t::pgsize_e) 0; i < pgent_t::size_max; i++)                                                                                
           {   
            if (! is_page_size_valid (i))
                continue;
            for (j = (mapnode_t::pgsize_e) 0; j < mapnode_t::size_max; j++)
                if (hw_pgshifts[i] == mdb_pgshifts[j])
                break;
            if (j == mapnode_t::size_max+1)
                panic ("mdb_pgshifts[] is not a superset of valid hw_pgshifts[]");
            }   
    ⑩、初始化内核时钟源
      get_timer()->init_global();
        void SECTION (".init")timer_t::init_global(void) 在kernel/src/glue/v4-mips64/timer.cc中实现
          get_interrupt_ctrl()->register_interrupt_handler(7, handle_timer_interrupt);
            interrupt_handlers[7] = (word_t) handle_timer_interrupt;
            定时器中断处理函数在kernel/src/glue/v4-mips64/timer.cc实现
      get_timer()->init_cpu();  与特定CPU相关的设置
        void SECTION (".init")timer_t::init_cpu(void) 在kernel/src/glue/v4-mips64/timer.cc中实现
          write_32bit_cp0_register(CP0_COUNT, 0);  清零Count Register寄存器
          write_32bit_cp0_register(CP0_COMPARE, TIMER_PERIOD);向Compare Register寄存器写入TIMER_PERIOD
          #define TIMER_MAX_RATE     3686400
          #define TIMER_PERIOD       (TIMER_MAX_RATE/100)
          compare = TIMER_PERIOD;  其中compare位于class timer_t : public generic_periodic_timer_t类中
          get_interrupt_ctrl()->unmask(7);
            unmask位于kernel/include/glue/v4-mips64/intctrl.h中
            get_idle_tcb()->arch.int_mask |= 1<<7;
            mips_cpu::set_cp0_status((1<<8)<<7);
    ⑪init_processor( 0, plat_bus_freq[0]/1000, plat_cpu_freq[0]/1000);  注册处理器到内核接口页
      a)、procdesc_t * pdesc = get_kip()->processor_info.get_procdesc(0);
        return num < CONFIG_SMP_MAX_CPUS ? &processor_descriptors[num] : NULL;
        # define CONFIG_SMP_MAX_CPUS        1    定义
        procdesc_t processor_descriptors[CONFIG_SMP_MAX_CPUS] UNIT ("kip.pdesc");  定义
        #define UNIT(x) __attribute__((section(".data." x)))    定义
      b)、pdesc->set_external_frequency(plat_bus_freq[0]/1000);
        external_freq = plat_bus_freq[0]/100;  在kernel/include/api/v4/procdesc.h中实现
      c)、pdesc->set_internal_frequency(plat_cpu_freq[0]/1000);
        internal_freq = plat_cpu_freq[0]/1000;  在kernel/include/api/v4/procdesc.h中实现
      d)、使处理器在KIP中可用,KIP(kernel Interface Page)
        if ( get_kip()->processor_info.processors < 0)
          get_kip()->processor_info.processors = 0;
          class processor_info_t结构体在kernel/include/api/v4/kernelinterface.h中定义
/* initialize the scheduler */ get_current_scheduler()->init(true);在kernel/src/api/v4/schedule.cc中实现
   void SECTION(".init") scheduler_t::init( bool bootcpu )
    ①、wakeup_list = NULL;    初始化唤醒链表
    ②、root_prio_queue.init();  初始化优先级队列,在kernel/include/api/v4/schedule.h中实现
      #define MAX_PRIO            255  最大优先级
      for(int i = 0; i < MAX_PRIO; i++)
        prio_queue[i] = (tcb_t *)NULL;
      max_prio = -1;
    ③、get_idle_tcb()->create_kernel_thread(NILTHREAD, &__idle_utcb);创建空闲线程
      #define NILTHREAD   (threadid_t::nilthread())
        static threadid_t nilthread()
          threadid_t tid;
          tid.raw = 0;
          return tid;
      在kernel/src/api/v4/thread.cc中实现
      void tcb_t::create_kernel_thread(threadid_t dest, utcb_t * utcb)
        a)、init(dest);
            allocate();
            utcb = NULL;space = NULL;  清utcb和space
            set_state(thread_state_t::aborted);
            set_saved_state (thread_state);
            partner = threadid_t::nilthread();
            set_saved_partner (threadid_t::nilthread());
            myself_global = dest;  设置全局id
            myself_local = NILTHREAD;
            resources.init(this);初始化线程资源
            queue_state.init();队列初始化
            send_head = NULL;
            get_current_scheduler()->init_tcb(this);初始化调度
            if (this != get_idle_tcb())添加除空闲线程之外的其他线程到present list
              enqueue_present();
            init_stack(); 初始化栈
        b)、this->utcb = utcb;
        c)、get_current_scheduler()->set_priority(this, 0);内核线程默认优先级0
    ④、get_idle_tcb()->myself_global.set_raw((word_t)0x1d1e1d1e1d1e1d1eULL);设置idle-magic
    ⑤、get_idle_tcb()->notify(idle_thread);
    ⑥、if( bootcpu )
        get_idle_tcb()->notify(init_all_threads);
get_idle_tcb ()
->notify (finalize_cpu_init, 0);    在TCB里面创建堆栈框架,所以下一个线程转换时能够将调用通知过程
   INLINE void tcb_t::notify (void (*func)(word_t), word_t arg1)
    ((mips64_switch_stack_t *)stack)--;
    ((mips64_switch_stack_t *)stack)->s8 = (word_t) func;
    ((mips64_switch_stack_t *)stack)->s0 = arg1;
    ((mips64_switch_stack_t *)stack)->ra = (word_t) mips64_return_from_notify1;
/* get the thing going - we should never return */ get_current_scheduler()->start();在kernel/src/api/v4/schedule.cc中实现
  void SECTION(".init") scheduler_t::start(cpuid_t cpuid)
    ①、get_idle_tcb()->set_cpu(cpuid);设置CPU工作在一个TCB中
      INLINE void tcb_t::set_cpu(cpuid_t cpu)在kernel/include/glue/v4-mips64/tcb.h中实现
        this->cpu = cpu;
        get_utcb()->processor_no = cpu;
    ②、initial_switch_to(get_idle_tcb());在kernel/include/glue/v4-mips64/tcb.h中实现
      a)、hw_asid_t new_asid = get_kernel_space()->get_asid()->get();
      b)、cache_t::flush_cache_all();
      c)、mips64_initial_switch_to((word_t)tcb->stack, new_asid, (word_t)tcb->get_space());
        汇编代码实现
printf(
"\nShould never get here!\nKernel Halted\n"); /* make sure we don't fall off the edge */ spin_forever(1); }

 

 

posted @ 2020-03-03 22:20  心缘-因缘  阅读(1215)  评论(0)    收藏  举报