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);
}
浙公网安备 33010602011771号