现在看的是怎样将系统引导进编制的操作系统内核。以《orang‘s os 一个操作系统的编制》为参考。首先要做的就是在存储介质的前512个字节上大作文章,写程序。而进内核,一种方案是自己写个16位汇编程序,放进512。用这个程序去引导内核,就像开源项目grub一样。但很明显,这样做起来,无论从技术和代码量上都不易 。我学着书中所说,还是用dos引导吧。先把原型做出来,再在上面增添功能。使用快速开发的思想,编制我的操作系统。

      一般对于80386以上的内核中,程序一般运行在32位环境中(64位,晕!不谈,那不是给人用的)。所以还需要先从16为跳到32位。

      总之,上面的步骤主要有三。

      一、将存储介质前512从内存07c00h处运行。

      二、从16位跳到32位。

      三、进内核。

     下面的代码是16->32的危险一跳。

; ==========================================
2 ; pmtest1.asm
3 ; 编译方法:nasm pmtest1.asm -o pmtest1.bin
4 ; ==========================================
5
6 %include "pm.inc"<span color="#0000ff"style="color: #0000ff;">; 常量, 宏, 以及一些说明</span>
7
8 org 07c00h <span color="#0000ff"style="color: #0000ff;">; 加载07c00h处cs=0000h,ip=07c00h(别人规定的)</span>








01 jmp LABEL_BEGIN ; 跳转到LABEL_BEGIN处
02
03 [SECTION .gdt]
04 ; GDT
05 ; 段基址, 段界限 , 属性
06 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
07 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
08 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
09 ; GDT 结束
10
11 GdtLen equ $ - LABEL_GDT ; GDT长度
12 GdtPtr dw GdtLen - 1 ; GDT界限
13 dd 0 ; GDT基地址
14
15 ; GDT 选择子
16 SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT ;32位代码段选择子
17 SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT ;显存选择子
18 ; END of [SECTION .gdt]
19
20 [SECTION .s16]
21 [BITS 16]
22 LABEL_BEGIN:
23 mov ax, cs
24 mov ds, ax
25 mov es, ax
26 mov ss, ax ;以上代码将当前的ds,es,ss全部指向cs代码段
27 mov sp, 0100h ;sp设置为0100h
28
29 ; 初始化 32 位代码段描述符
30 xor eax, eax ;eax清0
31 mov ax, cs ;存入cs
32 shl eax, 4 ;左移4位,扩展为20位地址
33 add eax, LABEL_SEG_CODE32 ;在cs的基础上加上LABEL_SEG_CODE32的地址偏移(相对于0)
01 mov word [LABEL_DESC_CODE32 + 2], ax ;将ax中的16位段地址移入描述符LABEL_DESC_CODE32对应的2~3字节
02 shr eax, 16 ;将eax的高16位移入低16位中
03 mov byte[LABEL_DESC_CODE32 + 4], al ;将al中的8位段地址移入描述符LABEL_DESC_CODE32对应的4字节中
04 mov byte[LABEL_DESC_CODE32 + 7], ah ;将ah中的8位段地址移入描述符LABEL_DESC_CODE32对应的7字节中
05
06 ; 为加载 GDTR 作准备
07 xor eax, eax ;eax清0
08 mov ax, ds ;ds移入ax
09 shl eax, 4 ;扩展为20位
10 add eax, LABEL_GDT ; eax <- gdt 基地址 ds+gdt基地址
11 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 将gdt基地址移入GdtPtr中
12
13 ; 加载 GDTR
14 lgdt [GdtPtr];将GdtPtr中的GDT界限和GDT基地址加载到寄存器gdtr中
15
16 ; 关中断
17 cli
18
19 ; 打开地址线A20-----前面的段地址已经扩展位20位
20 inal, 92h
21 or al, 00000010b
22 out92h, al
23
24 ; 准备切换到保护模式
25 mov eax, cr0 ;加载cr0到eax
26 or eax, 1 ;将cr0的PE置位1,打开保护模式
27 mov cr0, eax ;更改cr0
28
29 ; 真正进入保护模式
30 jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs,
31 ; 并跳转到 Code32Selector:0 处 SelectorCode32中段基址指向LABEL_SEG_CODE32偏移为0
32 ; END of [SECTION .s16]
33
34
35 [SECTION .s32]; 32 位代码段. 由实模式跳入.
36 [BITS 32]
37
38 LABEL_SEG_CODE32:
39 mov ax, SelectorVideo
40 mov gs, ax ; 视频段选择子(目的)
41
42 mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。
43 mov ah, 0Ch ; 0000: 黑底 1100: 红字
44 mov al, 'P'
45 mov [gs:edi], ax
46
47 ; 到此停止
48 jmp $
49
50 SegCode32Len equ $ - LABEL_SEG_CODE32
51 ; END of [SECTION .s32]
进入保护模式的主要步骤

  a.准备GDT

  b.用lgdt加载gdtr

  c.打开A20

  d.置cr0的PE位

  e.跳转,进入保护模式


 posted on 2011-03-18 09:12  文鬼  阅读(263)  评论(0编辑  收藏  举报