making an os NO.1 怎样进内核之一

 现在看的是怎样将系统引导进编制的操作系统内核。以《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.跳转,进入保护模式


你可能感兴趣的:(OS)