随笔-80  评论-24  文章-0  trackbacks-0
这个文件是从loader真正跳入内核后的routine。因此它最急需的工作当然是进行保护模式的重新初始化,包括重新加载gdt,以及开启分页机制、加载idt,跳入到c代码运行,先贴代码吧:

  1 PARAM_ADDR    equ 0xf0000 ; 在laoder中保存的bios参数的地址,此地址是相当于段基地址0x0的偏移量
  2 PDE_ADDR    equ 0x100000 ; 页目录表从1M地址开始, 大小4K,含有1024个表项
  3 PTE_ADDR    equ 0x101000 ; 页表紧接着页目录表开始
  4 
  5 extern set_idt
  6 extern cbegin
  7 
  8 global _start ; kernel程序入口,需要导出
  9 global gdt
 10 global gdtr
 11 global stacktop ; 内核态的堆栈顶
 12 
 13 [SECTION .text]
 14 _start:
 15     lgdt [gdtr] ; 重新加载新的全局描述符表
 16     jmp 0x08:new_gdt ; 使新的全局描述符表立即生效
 17 new_gdt:
 18     ;设置各个段寄存器
 19     mov ax, 0x10
 20     mov ds, ax
 21     mov es, ax
 22     mov gs, ax
 23     mov fs, ax
 24     mov ss, ax
 25     mov esp, stacktop ; 重新设置堆栈
 26 
 27     call set_idt ; 设置中断
 28 
 29     call setup_paging ; 开启分页机制
 30 
 31     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 32     ; 从下面这一指令之后便真正跳入c函数内执行
 33     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 34     call cbegin ; 跳转到cbegin函数执行,cbegin函数负责进程方面的初始化工作
 35 
 36 
 37 
 38 setup_paging:
 39     xor eax, eax
 40     xor ebx, ebx
 41     xor ecx, ecx
 42     xor edx, edx
 43     mov esi, PARAM_ADDR
 44     add esi, 0x2
 45     mov word ax, [esi] ; 扩展内存的大小(即1MB以后的内存的大小),以KB为单位,因此扩展内存最大64MB
 46     cmp ax, 0x08 ; 扩展内存大小不能小于8KB,因为我们保证至少要能存放页目录表和一个页表
 47     jb extended_mem_shortage
 48     cmp ax, 0xfbff ; 如果扩展内存大于63MB内存则报错
 49     ja too_many_mem
 50     add ax, 0x400 ; 扩展内存大小加上1MB等于总内存数量
 51     mov ebx, 0x1000
 52     div ebx ; 总内存数量(XKB)除以每个页表代表的内存数量(4KKB),即用X/4K即得总共应该分的页数
 53     mov ecx, eax ; 商在eax中,需要分的页数
 54     test edx, edx
 55     jz no_remainder
 56     inc ecx
 57 no_remainder:
 58     push ecx
 59 
 60     ; 开始初始化页目录表
 61     mov edi, PDE_ADDR
 62     mov eax, PTE_ADDR + 0x007 ; 页表首地址0x100000,属性是在内存中存在且普通用户可读可写
 63 write_pde:
 64     stosd
 65     add eax, 0x1000
 66     loop write_pde
 67 
 68     ; 开始初始化页表
 69     pop eax ; 页表个数
 70     ; 页表总数乘以每个页表含有的表项数目(1024个)则得到总共需要的表项数目
 71     mov ecx, 10
 72 goon_shl:
 73     shl eax, 1 ; 页表总数乘以每个页表含有的表项数目(1024个)则得到总共需要的表项数目
 74     jc too_many_mem
 75     loop goon_shl
 76     mov ecx, eax
 77     mov edi, PTE_ADDR
 78     mov eax, 0x007 ; 从物理地址0x0开始,属性是在内存中存在且普通用户可读可写
 79 write_pte:
 80     stosd
 81     add eax, 0x1000 ; 每页内存大小为4KB
 82     loop write_pte
 83 
 84     mov eax, PDE_ADDR
 85     mov cr3, eax ; cr3高20位存放pde的地址的高20位
 86     mov eax, cr0
 87     or eax, 0x80000000
 88     mov cr0, eax ; 打开cr0的最高一位PG位
 89     ret
 90 
 91 extended_mem_shortage:
 92     hlt
 93 
 94 too_many_mem:
 95     hlt
 96 
 97 [SECTION .data]
 98 gdt:
 99         ; 第一个描述符空,不使用
100         db 0x00,    0x00
101         db 0x00,    0x00,    0x00
102         db 0x00,    0x00
103         db 0x00
104 
105         ; 第二个描述符的段基地址为0;
106         ; 界限为0xfffff,段界限粒度为4KB;
107         ; 是可执行可读的32位代码段
108         db 0xff,    0xff
109         db 0x00,    0x00,    0x00
110         db 0x9a,    0xcf
111         db 0x00
112 
113         ; 第三个描述符的段基地址为0;
114         ; 界限为0xfffff,段界限粒度为4KB;
115         ; 是可读可写32位数据段
116         db 0xff,    0xff
117         db 0x00,    0x00,    0x00
118         db 0x92,    0xcf
119         db 0x00
120         
121         ; gdt表共可存放256个段描述符
122         times 253 * 8 db 0
123 
124 gdtr:                dw $ - gdt - 1
125                     dd gdt
126 
127 [SECTION .bss]
128 stackbase resb    4 * 1024 ;4KB堆栈大小
129 stacktop: ;堆栈顶部,向下扩展

可以看到新的gdt总共有256项,其中第一项依然是不使用的,不过有些操作系统为了节省内存,居然将gdtr放到第一项中(比如menuetOS),这个想法比较特别~
不过我觉得8字节没有必要这么节省拉:)所以我们选择第一个gdt项空。之后是cs段descriptor、ss段descriptor,这两个位置最好不要变动,因为1、大部分的操作系统都是这么安排的,因为之后的进程切换、中断处理的时候都需要用到0x8和0x16这两个选择子;2、Intel奔腾2之后的机型都支持sysenter和sysexit的快速系统自陷即系统调用指令,这两个指令是需要cs和ds、ss选择子为0x8和0x16的,如果改变位置则这两个高级指令无法使用了;3、也没有必要非得把这两个descriptor放到别的地方,已经够简洁了~另外在bss段开辟了4KB大小的堆栈供内核使用。
jmp 0x8:net_gdt这条指令是来自于《操作系统设计与实现》,它将会刷新cs段寄存器高速缓存,启用新的gdt。
set_idt暂时先不说,因为它在下一个文件int.s中,下一节再讲解。
之后是启动分页机制,特别注意页目录表在1MB内存起始处,之后放置的是页表,不过这只是随意写的代码而已,因为之后当写内存管理器的时候这儿的分页机制会被修改,而且内核空间页表和用户空间页表是不同的,理应不能放到一起。
最后是跳转到cbegin函数执行c函数,注意的是该c函数永远不会返回,除非我的操作系统厌恶了生存想要崩溃了~^_!
posted on 2011-12-20 00:25 myjfm 阅读(491) 评论(0)  编辑 收藏 引用 所属分类: 操作系统

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理