1.c运行环境的初始化

来源:互联网 发布:linux tomcat启动很慢 编辑:程序博客网 时间:2024/05/22 06:33

1.c运行环境的初始化

源代码目录src/sandnix/kernel/hal/init/arch
这部分干的活可以归为以下几点

  • 让cpu处在正确的工作模式.(bootloader不总是对的).
  • 关中断(没中断向量/描述符表万一来了个中断乐子就大了).
  • 开分页(不把代码跳到内核空间难道访问全局变量的时候挨个算偏移量?)
  • 保存bootloader传来的信息(不保存启动参数,内存信息啥的咋办).

x86

.global     _start.global     gdt.global     kernel_header.global     tss_desc_table.section    .data//GDT表gdt:    SEGMENT_DESCRIPTOR  0,              0,                  0descriptor_kernel_data:    SEGMENT_DESCRIPTOR  0,              0xFFFFF,            DA_DRW | DA_DPL0 | DA_32descriptor_kernel_code:    SEGMENT_DESCRIPTOR  0,              0xFFFFF,            DA_CR | DA_DPL0 | DA_32descriptor_user_data:    SEGMENT_DESCRIPTOR  0,              0xFFFFF,            DA_DRW | DA_DPL3 | DA_32descriptor_user_code:    SEGMENT_DESCRIPTOR  0,              0xFFFFF,            DA_CR | DA_DPL3 | DA_32tss_desc_table:.rept       MAX_CPU_NUM    SEGMENT_DESCRIPTOR  0,              0x67,               DA_386TSS | DA_DPL0.endrgdt_end:gdtr_value:    .word       (gdt_end - gdt - 1)gdt_addr:    .long       gdt.section    .text.align      8//描述内核映像信息的结构体,编译时由脚本填充kernel_header:    //magic    .long   KERNEL_HEADER_MAGIC    //code_start    .long   0    //code_size    .long   0    //data_start    .long   0    //data_size    .long   0    //header_size    .long   _kernel_header_end - kernel_header    //checksum    .long   0x100000000 - ((KERNEL_HEADER_MAGIC + (_kernel_header_end - kernel_header)) & 0xFFFFFFFF)_kernel_header_end:    .long   0/* Step 1 : 检查引导协议类型.咋检查看multiboot2的文档 */#if BOOTLOADER == MULTIBOOT2    //EAX == Magic.EBX = Kernel parameters_start:    cli    //Check bootloader    cmpl    $0x36D76289, %eax    je      _BOOTLOADER_CHECKED    //if(eax != 0x36D76289) {        //不是的话就重启吧        movb    $0xFE, %al        outb    %al, $0x64        hlt    //}_BOOTLOADER_CHECKED:    //对的话就把引导信息的地址压栈    pushl   %ebx#endif/* Step 2 : 准备C的运行环境 */    //call/pop/sub组合计算偏移量,这招过去很多文件型病毒也爱用    call    _ADDR_1_ADDR_1:    popl    %eax    subl    $_ADDR_1, %eax //eax = offset    //Write gdt address    movl    $gdt, %edx    addl    %eax, %edx    movl    $gdt_addr, %ebx    addl    %eax, %ebx    movl    %edx, (%ebx)    //Load GDT    movl    $gdtr_value, %ebx    addl    %eax, %ebx    lgdt    (%ebx)    //Load segments    movw    $SELECTOR_U_DATA, %ax    movw    %ax, %ds    movw    %ax, %es    movw    %ax, %fs    movw    %ax, %gs    //开分页,这个函数是mmu模块提供的,用c写的,访问个全局变量都要计算偏移,相当的蛋疼    call    start_paging    //跳到内核空间,顺便加载cs    ljmpl   $SELECTOR_K_CODE, $_KERNEL_MEM_KERNEL_MEM:    //Reload stack    //弹出引导信息    popl    %edi    movl    $init_stack, %ebx    addl    $DEFAULT_STACK_SIZE, %ebx    movl    %ebx, %ebp    movl    %ebx, %esp    //将刚才弹出的引导信息压栈,这样正好作为内核主函数的参数    push    %edi    //Reload GDT    //Write gdt address    movl    $gdt, gdt_addr    //Load GDT    movl    $gdtr_value, %eax    lgdt    (%eax)    //FPU    fninit    movl    $0x80010021, %eax    movl    %eax, %cr0/* Step 3 : Call c code. */    //调用主函数    call    kinit

ARM

.global     _start.global     kernel_header.section    .text.align      8//跟上面一样kernel_header:    //magic    .long   KERNEL_HEADER_MAGIC    //code_start    .long   0    //code_size    .long   0    //data_start    .long   0    //data_size    .long   0    //header_size    .long   _kernel_header_end - kernel_header    //checksum    .long   0x100000000 - ((KERNEL_HEADER_MAGIC + (_kernel_header_end - kernel_header)) & 0xFFFFFFFF)_kernel_header_end:    .long   0_start:    //保证处于SVC模式并且屏蔽掉IRQ和FIQ    ldr     r5, =0x000000D3    msr     spsr, r5    msr     cpsr, r5    //计算偏移,原理和X86的一样_offchk_addr:    mov     r5, pc    sub     r5, r5, #8    ldr     r6, =_offchk_addr    sub     r5, r5, r6      //r5 = offset    //加载内核栈    ldr     sp, =init_stack    add     sp, sp, r5    ldr     r6,=DEFAULT_STACK_SIZE    add     sp, sp, r6#if BOOTLOADER == UBOOT    //把参数压栈    stmfd   sp!, {r2}#endif    //开分页    bl      start_paging    //重定位栈指针    sub     sp, sp, r5    //把参数弹到r0    ldmfd   sp!, {r0}    //调用主函数    ldr     r1, =kinit    mov     pc, r1
0 0