一个操作系统的实现:保护模式

今天学习了保护模式,依据书上的内容以及大灰狼老师的视频,终于完成自己写的保护模式。

[BITS 16]                           ;表示以下为段位16位

org      07c00h                 ;这是由于系统会将代码加载到7C00处

jmp start

gdt_table_start:

            gdt_null:                                            

                     dd          0h

                     dd         0h                ;Intel 规定描述符表的第一个描述符必须为空描述符

         gdt_data_addr          equ      $-gdt_table_start

        gdt_data:

                   dw    07FFh             ;数据段的界值,一个数据段、代码段规定为8M大小

                   dw    0h                    ;段基址的0~18位

                   db    0h                     ;段基址的19~23位

                   db    10010010b     ;第一个1,表示P,是描述符对地址的转换是否有效,有效为1

                                                      ;第二个1,表示DT,表示是系统段还是存储段,为1表示系统段

                                                      ;第三个1,与0010一起表示type类型,即是可读可写的数据段还是可读可执行的代码段

                                                      ;段属性的第六字节

                  db    11000000b      ;第一个1,表示是数据段大小4G,为0则表示64K;代码段是32位,为0则表示16位

                                                      ;第二个1表示段界限粒度为字节,0则表示为4K

                                                      ;段属性的第七字节

                  db     0h                      ;基地址

    

gdt_code_addr equ $-gdt_table_start

gdt_code:

dw 07FFh ;代码段的界值,一个数据段、代码段规定为8M大小

dw 1h ;段基址的0~18位

db 80h ;段基址的19~23位

db 10011010b ;第一个1,表示P,是描述符对地址的转换是否有效,有效为1

;第二个1,表示DT,表示是系统段还是存储段,为1表示系统段

;第三个1,与1010一起表示type类型,即是可读可写的数据段还是可读可执行的代码段

;段属性的第六字节

db 11000000b ;第一个1,表示是数据段大小4G,为0则表示64K

;第二个1表示代码段是32位,为0则表示16位

;段属性的第七字节

db 0h ;基地址

gdt_video_addr equ $-gdt_table_start

gdt_video:

dw 01FFh ;代码段的界值,可以为任意值

dw 8000h ;段基址的0~18位

db 0Bh ;段基址的19~23位

db 10010010b ;第一个1,表示P,是描述符对地址的转换是否有效,有效为1

;第二个1,表示DT,表示是系统段还是存储段,为1表示系统段

;第三个1,与1010一起表示type类型,即是可读可写的数据段还是可读可执行的代码段

;段属性的第六字节

db 11000000b ;第一个1,表示是数据段大小4G,为0则表示64K

;第二个1表示代码段是32位,为0则表示16位

;段属性的第七字节

db 0h ;基地址

gdt_table_end:

 

                gdtr_addr:

                           dw        gdt_table_end-gdt_table_start-1                 ;段描述符表长度,GDTR寄存器为48位

                           dd         gdt_table_start                                               ;段描述符表基地址

 

    start:

       ;初始化数据段描述符

      xor      eax  ,   eax

      mov   eax  ,    data_32

      mov  word [gdt_data+2]  ,ax

      shr    eax  ,  16

      mov  byte [gdt_data+4]  , al

      mov byte [gdt_data+7]   ,ah

  

;初始化代码段描述符

xor eax , eax

mov eax , code_32

mov word [gdt_code+2] ,ax

shr eax , 16

mov byte [gdt_code+4] , al

mov byte [gdt_code+7] ,ah

 

;关闭中断向量表,相当于删除以前的16位中断向量表,为装入32位中断向量表做准备

cli

 

;加载GDT描述表的大小和基地址放入gdtr寄存器

lgdt  [gdtr_addr]

 

;打开A20地址线,以便能够访问超过1M的地址内存

in    al  ,  92h

or   al  ,00000010b

out  92h , al

 

;打开保护模式允许

mov  eax , cr0

or    eax ,1

mov cr0  , eax

 

;跳转到保护模式下的32位地址处

jmp    gdt_code_addr:0

 

[BITS  32]

    data_32:

       dd   "my os!"

    code_32:

      mov   ax , gdt_data_addr

      mov ds  , ax

     mov  ax  , gdt_video_addr

    mov  gs  ,ax

    mov edi ,(80*20+30)*2                       ;在屏幕第20行第30列处显示数据my os!

    mov ah  , 0ch                                       ;黑底红字

   mov bx  ,0

    mov cx  ,6

s:

    mov al  ,  [ds:bx]

    mov [gs:edi]  , al

    mov [gs:edi+1]  , ah

    inc  bx

    add edi  ,2

    loop  s

  

  jmp  $

times  510-($-$$)     db  0

dw 0aa55h

                       

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

                

 

你可能感兴趣的:(一个操作系统的实现:保护模式)