码迷,mamicode.com
首页 > 其他好文 > 详细

一,内核加载程序

时间:2014-11-30 16:46:29      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   io   ar   color   os   使用   sp   

加载程序不是内核的重点,我们只需知道内核被加载到什么地方,内核的入口地址是什么即可,一些技术细节没必要过分关心。

xv6的内核加载程序由两个文件组成:bootasm.S和bootmain.c

bootasm.s的主要目的就是由实模式进入保护模式,下面是bootasm.s的代码注释:

 1 #加载器被BIOS加载到0x7c00地址处,此时cs = 0, eip = 7c00。其他寄存器的值
 2 #不关心
 3 
 4 #include "asm.h"
 5 #include "mmu.h"
 6 .code16
 7 .global start
 8 start:
 9     cli
10 
11     xorw    %ax, %ax
12     movw    %ax, %ds
13     movw    %ax, %es
14     movw    %ax, %ss
15 
16 #打开A20总线,这是个历史遗留问题
17 seta20.1:
18     inb     $0x64,%al
19     testb   $0x2,%al
20     jnz     seta20.1
21 
22     movb    $0xd1,%al
23     outb    %al,$0x64
24 
25 seta20.2:
26     inb     $0x64,%al
27     testb   $0x2,%al
28     jnz     seta20.2
29 
30     movb    $0xdf,%al
31     outb    %al,$0x60
32 
33 #进入保护模式
34     lgdt    gdtdesc
35     movl    %cr0, %eax
36     orl     $CR0_PE, %eax
37     movl    %eax, %cr0
38 
39     ljmp    $(SEG_KCODE<<3), $start32
40 
41 #保护模式代码
42 .code32
43 start32:
44 #设置段寄存器的值 
45     movw    $(SEG_KDATA<<3), %ax
46     movw    %ax, %ds
47     movw    %ax, %es
48     movw    %ax, %ss
49     movw    $0, %ax
50     movw    %ax, %fs
51     movw    $ax, %gs
52 
53 #设置栈指针
54     movl    $start, %esp
55     call    bootmain
56 
57 #不应该从bootmain函数中返回,如果返回了,进入无限循环
58 
59 spin:
60     jmp     spin
61 #加载器使用的GDT
62 .p2align    2
63 gdt:
64     SEG_NULLASM
65     SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   #代码段 
66     SEG_ASM(STA_W, 0x0, 0xffffffff)         #数据段
67 
68 gdtdesc:
69     .word   (gdtdesc - gdt - 1)
70     .long   gdt

 

bootmain.c主要是把内核可执行文件加载到内存中,xv6内核的可执行文件是elf格式,所以要对elf文件格式有所了解。

这里只用到elf文件格式的两个表头,只需了解这两个表头的含义即可。

第一个表头是elf头部结构,位于elf文件的首部

#define EI_NIDENT 16
typedef struct{
    unsigned char e_ident[EI_NIDENT];    //目标文件标识信息
    Elf32_Half e_type;                             //目标文件类型
    Elf32_Half e_machine;                       //目标体系结构类型
    Elf32_Word e_version;                      //目标文件版本
    Elf32_Addr e_entry;                          //程序入口的虚拟地址,若没有,可为0
    Elf32_Off e_phoff;                            //程序头部表格(Program Header Table)的偏移量(按字节计算),若没有,可为0
    Elf32_Off e_shoff;                            //节区头部表格(Section Header Table)的偏移量(按字节计算),若没有,可为0
    Elf32_Word e_flags;                        //保存与文件相关的,特定于处理器的标志。标志名称采用 EF_machine_flag的格式。
    Elf32_Half e_ehsize;                        //ELF 头部的大小(以字节计算)。
    Elf32_Half e_phentsize;                   //程序头部表格的表项大小(按字节计算)。
    Elf32_Half e_phnum;                      //程序头部表格的表项数目。可以为 0。
    Elf32_Half e_shentsize;                  //节区头部表格的表项大小(按字节计算)。
    Elf32_Half e_shnum;      //节区头部表格的表项数目。可以为 0。
    Elf32_Half e_shstrndx;  //节区头部表格中与节区名称字符串表相关的表项的索引。如果文件没有节区名称字符串表,此参数可以为 SHN_UNDEF。
}Elf32_Ehdr;

我们只用到这个结构中的两项:e_phoff(程序头部表格的偏移量)和 e_phnum(程序头部表格的表项数目)。

 

第二个结构是程序头部,指示该elf文件的哪些部分需要被加载到内存中去,一个程序头部结构对应一个要被加载入内存的文件段。

typedef struct {
    Elf32_Word p_type;    //段类型
    Elf32_Off p_offset;      //段位置
    Elf32_Addr p_vaddr;    //给出段的第一个字节将被放到内存中的虚拟地址
    Elf32_Addr p_paddr;    //仅用于与物理地址相关的系统中
    Elf32_Word p_filesz;     //给出段在文件映像中所占的字节数
    Elf32_Word p_memsz;    //给出段在内存映像中占用的字节数
    Elf32_Word p_flags;    //与段相关的标志
    Elf32_Word p_align;    //对齐
} Elf32_phdr;

该结构中的p_offset指明该段在文件中的偏移,p_filesz指明该段的大小,p_paddr指明要被加载进的物理地址,有了这三个信息,就可以加载内核可执行文件了。

 

bootmain.c所做的工作就是根据以上两个结构的内容把内核可执行文件的某些部分加载进指定的物理内存处。

最后跳到内核的入口处,开始执行内核代码,内核被加载成功。

一,内核加载程序

标签:des   style   blog   io   ar   color   os   使用   sp   

原文地址:http://www.cnblogs.com/zhanjunling/p/4133157.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!