操作系统实现之保护模式

保护模式主要是为了防止用户程序故意使坏.而且用户所引用的地址都是指向真实的物理地址.跟内核属于同特权级.不利于安全.另外保护模式将是32/64位.大家所说的实模式一般指的是32位的cpu在16位模式下的状态.不是指的是16位cpu.本来没有实模式这个说法.不过后来出现保护模式.于是就出现了实模式说法


保护模式下的改变

通用寄存器扩展为32位

段寄存器保存的不再是段基址,而是段选择子(段描述符的索引)

段基址保存在段描述符中,而段描述符保存在全局描述符表(GDT)中. 而全局描述符表保存在专门的寄存器gdtr,加载时用lgdt指令进行加载



全局描述符表(本简单kernel没用局部描述符表)所存储的描述符格式


之所以如此..混乱.完全是由于历史兼容原因

再来看看段选择子(保存在段寄存器中)的定义



保护模式下的选址方式发生了改变
一开始从段寄存器获取段选择子.通过段选择子的索引位*8(乘以8是因为.一个段描述符是8个字节)+gdtr保存的全局描述符表基址.  得到段基址

然后加上偏移寄存器.得到实际地址

如何进入保护模式:

1.打开A20(历史遗留问题.第21根地址线)

2.加载dgt

3.将cr0的pe位定义为1(表示进入保护模式)

-------------------------配置文件boot.inc的定义----------------

  1. ;-------------   LOADER和KERNEL   ----------  
  2. loader_base_addr equ 0X900              ;加载位置  
  3. loader_stack_top equ loader_base_addr   ;栈指向的位置  
  4. loader_start_sector equ 0X2             ;loader存储到第二个扇区  
  5.   
  6. ;--------------   GDT描述符属性  -----------  
  7. desc_g_4k   equ   1_00000000000000000000000B  ;描述符的g位为4k粒度   
  8. desc_d_32   equ    1_0000000000000000000000B  ;表示是32位还是16位  
  9. desc_l      equ     0_000000000000000000000B    ;  64位代码标记,此处标记为0便可。  
  10. desc_avl    equ      0_00000000000000000000B    ;  CPU不用此位,暂置为0    
  11. desc_limit_code2  equ 1111_0000000000000000B  ;段的第二部分界限  
  12. desc_limit_data2  equ desc_limit_code2  
  13. desc_limit_video2  equ 0000_000000000000000B  ;  
  14. desc_p      equ       1_000000000000000B  
  15. desc_dpl_0  equ        00_0000000000000B        ;段描述符特权级  
  16. desc_dpl_1  equ        01_0000000000000B  
  17. desc_dpl_2  equ        10_0000000000000B  
  18. desc_dpl_3  equ        11_0000000000000B  
  19. desc_s_code equ          1_000000000000B  
  20. desc_s_data equ   desc_s_code  
  21. desc_s_SYS  equ          0_000000000000B  
  22. desc_type_code  equ       1000_00000000B    ;X=1,C=0,R=0,A=0 代码段是可执行的,非依从的,不可读的,已访问位A清0.    
  23. desc_type_data  equ       0010_00000000B    ;X=0,E=0,W=1,A=0 数据段是不可执行的,向上扩展的,可写的,已访问位A清0.  
  24. ;段的24位  
  25. desc_code_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_code2 + desc_p + desc_dpl_0 + desc_s_code + desc_type_code + 0X00  
  26. desc_data_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_data2 + desc_p + desc_dpl_0 + desc_s_data + desc_type_data + 0X00  
  27. desc_video_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_video2 + desc_p + desc_dpl_0 + desc_s_data + desc_type_data + 0X0B  
  28.   
  29. ;--------------   选择子属性  ---------------  
  30. rpl0  equ   00B  
  31. rpl1  equ   01B  
  32. rpl2  equ   10B  
  33. rpl3  equ   11B  
  34. ti_gdt   equ   000B  
  35. ti_ldt   equ   100B  
  36.   
  37. ;-------------  PROGRAM TYPE 定义   --------------  
  38. pt_null equ 0  


-----------------mbr.S的定义(改动只有就是从扇区读取4个扇区.而不是1个.因为loader.bin扩充了)----------------------------
  1. %include "boot.inc"  ;保存有关加载程序位置.源跟目的  
  2. section mbr vstart=0x7c00  
  3. jmp  near start  
  4. message db 'ZYW_OS start'  
  5. start:  
  6. ;ds:si指向数据源.es:di指向显存.  
  7.   mov sp,0x7c00   ;栈顶,栈成长的方向向上  
  8.   mov ax,0xb800     
  9.   mov es,ax       ;es指向显存位置  
  10.   
  11. ; 清屏(摘自百度)  
  12. ;利用0x06号功能,上卷全部行,则可清屏。  
  13. ; -----------------------------------------------------------  
  14. ;INT 0x10   功能号:0x06       功能描述:上卷窗口  
  15. ;------------------------------------------------------  
  16. ;输入:  
  17. ;AH 功能号= 0x06  
  18. ;AL = 上卷的行数(如果为0,表示全部)  
  19. ;BH = 上卷行属性  
  20. ;(CL,CH) = 窗口左上角的(X,Y)位置  
  21. ;(DL,DH) = 窗口右下角的(X,Y)位置  
  22. mov ax,0x0600  
  23. mov bx,0x0700  
  24. mov cx,0           ; 左上角: (0, 0)  
  25. mov dx,0x184f      ;  右下角(80,25),  
  26. int 10h                 
  27.   
  28. mov si,message  
  29. mov di,0  
  30. mov cx,start-message  
  31. zyw:  
  32.    movsb  
  33.    mov byte [es:di],0xA4  ;控制背景跟颜色  
  34.    inc di  
  35. loop zyw   
  36.   
  37. mov eax,loader_start_sector   ;eax保存加载程序的位置  
  38. mov bx,loader_base_addr       ;bx保存加载到哪个区域  
  39. mov cx,4                     ;cx保存加载几个扇区(从eax开始)  
  40. call read_disk   
  41. jmp   loader_base_addr    
  42.   
  43. read_disk:       
  44.     push eax  
  45.     mov dx,0x1f2   ;硬盘端口0x1f2 ,设置要读取多少数据  
  46.     mov al,cl      ;这里表示读取一个  
  47.     out dx,al    
  48.     pop eax  
  49.   
  50. ;将lba地址存入0x1f3-0x1f6处  
  51.     mov dx,0x1f3  
  52.     out dx,al  
  53.    push cx  
  54.     mov cl,8  
  55.     shr eax,cl  
  56.     mov dx,0x1f4  
  57.     out dx,al  
  58.   
  59.     shr eax,cl  
  60.     mov dx,0x1f5  
  61.     out dx,al  
  62.   
  63.     shr eax,cl  
  64.     and al,0x0f  
  65.     or al,0xe0  
  66.     mov dx,0x1f6  
  67.     out dx,al  
  68.   pop cx  
  69.   
  70.   
  71.     ;向0x1f7写入命令  
  72.     mov dx,0x1f7  
  73.     mov al,0x20  
  74.     out dx,al  
  75.           
  76. noready:  
  77.     nop  
  78.     in al,dx  
  79.     and al,0x88   
  80.     cmp al,0x08  
  81. jnz noready  
  82.          
  83.     ;开始从0x1f0端口读取数据  
  84.     mov ax,cx    
  85.     mov dx,256  
  86.     mul dx  
  87.     mov cx,ax  
  88.     mov dx,0x1f0  
  89.   
  90. readdata:  
  91.    in ax,dx  
  92.    mov [bx],ax  
  93.    add bx,2  
  94.    loop readdata  
  95.    ret  
  96.   
  97.   
  98.    times 510-($-$$) db 0  
  99.    db 0x55,0xaa  


-----------------loader的定义-------------------------------

  1. %include "boot.inc"  
  2. section loader vstart=loader_base_addr  
  3. jmp start  
  4. ;------------全局描述符表的定义   
  5. gdt_base:   
  6.                    dd 0x00000000    ;全局描述表.第一个描述符要为空  
  7.                      dd 0x00000000  
  8.   
  9. code_base:   
  10.                      dd 0x0000FFFF  
  11.                      dd desc_code_high4  
  12.   
  13. data_stack_desc:  
  14.                      dd 0x0000ffff  
  15.                      dd desc_data_high4  
  16.   
  17. video_desc:   
  18.                     dd 0x80000007   ;段界限 limit=0x7fff.基址位于0xb8000  
  19.                     dd desc_video_high4  
  20.   
  21. ;---------GDT的属性  
  22. gdt_size  equ $-gdt_base  ;GDT大小  
  23. gdt_limit equ gdt_size    ;GDT限制  
  24. time 60 dq 0  ;预留60个描述符的空位置  
  25.   
  26. ;----------定义段选择子-------------  
  27. selector_code equ (0x0001<<3)+ti_gdt+rpl0  
  28. selector_data equ (0x0002<<3)+ti_gdt+rpl0  
  29. selector_video eque(0x0003<<3)+ti_gdt+rpl0  
  30.   
  31.   
  32. ;定义gdt的指针,前2个字节为gdt界限,后4个字节为gdt起始地址  
  33. gdt_ptr dw gdt_limit  
  34.               dd gdt_base  
  35.                 
  36.   
  37. ;-----进入保护模式----------  
  38. in al,0x92  
  39. or al,0000_0010B  
  40. out 0x92,al  
  41.   
  42. ;----------加载GDT----------  
  43. lgdt [gdt_ptr]  
  44.   
  45. ;---------cr0第0位置为1,表示打开保护模式-----------  
  46. mov eax,cr0  
  47. or  eax,0x00000001  
  48. mov cr0,eax  
  49.   
  50. jmp dword selector_code:p_mode_start:  
  51. [bits 32]  
  52. p_mode_start:  
  53.     mov ax,selector_data  
  54.     mov ds,ax  
  55.     mov es,ax  
  56.     mov ss,ax  
  57.     mov esp,loader_stack_top  
  58.     mov ax,selector_video  
  59.     mov gs,ax  
  60.       
  61.     mov byte [gs:160],'P'  
  62.       
  63.     jmp $  
显示效果如图


<bochs:3> creg
CR0=0x60000011: pg CD NW ac wp ne ET ts em mp PE

从上可以看出 PE位已经置为1了


最后loader.S定义了 

  1. mov byte [gs:160],'P'  

最终显示效果.如果成功进入了保护模式.就会出现P这个字符



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值