卓一笔记---用bochs调试实模式到保护模式转换程序

    古人诚不欺余,书读百遍其义自见.研究了5天,终于把于渊同志所写的实模式到保护模式的跳转的初级操作系统程序看懂了.文章虽艰涩难懂,但收获亦颇丰.

    Intel8086系统的实模式是16位寻址,往后的80386是32位寻址.在保护模式下是32位寻址,Intel8086从实模式跳转到保护模式需要将寻址格式进行切换由16位物理寻址变成16位线性寻址.下面这段程序演示了如何从实模式跳转到保护模式.

  1).首先构建pm.inc文件如下,此文件中定义了三个常量,和一个全局描述符宏,该宏可以将传进来的参数自动转换成8字节的GDT表中的全局描述符(32位寻址时用来描述分段地址).

1.1)全局描述符可参考文献:

​ https://blog.csdn.net/u014774781/article/details/47706213

 

 https://blog.csdn.net/wrx1721267632/article/details/52056910

 https://blog.csdn.net/me1171115772/article/details/51750442

 https://www.docin.com/p-495926832.html

DA_32  EQU 4000h ;32位段DA_DRW    EQU  92h  ; 存在的可读写数据段属性值DA_C  EQU  98h  ;存在的只执行代码段属性;描述符定义,传进来的参数会自动装到对应的字节中;usage:Descriptor Base,Limit,Attr%macro Descriptor 3       dw %2&0FFFFh ;段界限1       dw %1&0FFFFh ;段基址1       db (%1>>16)&0FFh ;段基址2       dw ((%2>>8)&0F00h)|(%3&0F0FFh) ;属性1 + 段界限2 + 属性2       db (%1>>24)&0FFh ;段基址3%endmacro ;共8个字节

2)创建后pm.inc后可以创建相应的pmtest1.asm文件如下:

; ==========================================; pmtest1.asm; 编译方法:nasm pmtest1.asm -o pmtest1.bin; ==========================================%include "pm.inc" ;常量,宏,以及一些说明org 07c00hjmp LABEL_BEGIN  ;跳到开始处执行,此时不会修改cs,cs仍然为0,偏移地址会加上7c00[SECTION .gdt] ;定义GDT全局描述符号(为(段地址,段界限,属性)三元组,占8字节空间)LABEL_GDT: Descriptor 0,0,0 ;空描述符  LABEL_DESC_CODE32:Descriptor 0,SegCode32Len-1,DA_C+DA_32 ;指向32位保护模式非一致代码段LABEL_DESC_VIDEO:Descriptor 0B8000h,0ffffh,DA_DRW ;显存(显卡)首地址描述符;GDT结束GdtLen equ $-LABEL_GDT ;GDT长度GdtPtr dw GdtLen-1 ;GDT界限       dd 0   ;GDT基地址;GDT选择子SelectorCode32 equ LABEL_DESC_CODE32-LABEL_GDT;这里比较特殊,各个描述符号的最右侧3位都为0,因此相减后,就是描述符在GDT表中的索引SelectorVideo  equ LABEL_DESC_VIDEO-LABEL_GDT;END of  [SECTION .gdt][SECTION .s16][BITS 16]LABEL_BEGIN:   mov ax,cs   mov ds,ax   mov es,ax   mov ss,ax   mov sp,0100h;初始化32位代码段全局描述符的段基址   xor eax,eax   mov ax,cs   shl eax,4   add eax,LABEL_SEG_CODE32   mov word [LABEL_DESC_CODE32+2],ax ;相对于基址cs的偏移   shr eax,16   mov byte [LABEL_DESC_CODE32+4],al   mov byte [LABEL_DESC_CODE32+7],ah   ;为加载GDT表做准备,先将GDT表的界限和起始地址找到存到Gdtptr中   xor eax,eax   mov ax,ds   shl eax,4   add eax,LABEL_GDT   mov dword [GdtPtr + 2],eax ;将GDT的基地址放好   lgdt  [GdtPtr]  ;将GDT表加载进来,后面可以访问GDT表中的值   ;关中断   cli   ;打开地址线A20   in al,92h   or al,00000010b   out 92h,al   ;准备切换到保护模式   mov eax,cr0   or eax,1   mov cr0,eax   ;真正进入保护模式   jmp dword SelectorCode32:0 ;执行这句话,为了将SelectorCode32                              ;指向的32为保护模式代码载入cs中                              ;并跳转到SelectorCode32:0处   ;END of  [SECTION .s16]   [SECTION .s32][BITS 32]LABEL_SEG_CODE32:   mov  ax,SelectorVideo   mov  gs,ax ;视屏段选择子加载进gs   mov  edi,(80*11 + 79)*2 ;屏幕第11行,79列   mov  ah,0Ch      ;0,为黑字,c为红字   mov  al,'P'     ;要显示的字符   mov   [gs:edi],ax   ;到此停止   jmp $       SegCode32Len equ $-LABEL_SEG_CODE32   ;END of  [SECTION .s32]

3.用命令nasm pmtest1.asm -o pmtest1.bin编译后,得到下面的文件

4.将上节创建的a.img,boshsrc拷贝到当前工作目录,并用

dd if=pmtest1.asm of=a.img bs=512 count=1 conv=notrunc;

将pmtest1.asm刻录到a.img中.

5.执行bochs -f bochsrc,在命令窗口中先输入6再输入c得到下面的界面,界面上会输出一个P,P其实就是由保护模式输出的.

6.此程序也可以编译成com文件在dos下运行.即将pmtest1.asm改成pmtest1dos.asm文件(将org 7c00h改成org 0100h即可),如下

; ==========================================; pmtest1.asm; 编译方法:nasm pmtest1.asm -o pmtest1.bin; ==========================================%include "pm.inc" ;常量,宏,以及一些说明org 0100hjmp LABEL_BEGIN  ;跳到开始处执行,此时不会修改cs,cs仍然为0,偏移地址会加上7c00[SECTION .gdt] ;定义GDT全局描述符号(为(段地址,段界限,属性)三元组,占8字节空间)LABEL_GDT: Descriptor 0,0,0 ;空描述符  LABEL_DESC_CODE32:Descriptor 0,SegCode32Len-1,DA_C+DA_32 ;指向32位保护模式非一致代码段LABEL_DESC_VIDEO:Descriptor 0B8000h,0ffffh,DA_DRW ;显存(显卡)首地址描述符;GDT结束GdtLen equ $-LABEL_GDT ;GDT长度GdtPtr dw GdtLen-1 ;GDT界限       dd 0   ;GDT基地址;GDT选择子SelectorCode32 equ LABEL_DESC_CODE32-LABEL_GDT;这里比较特殊,各个描述符号的最右侧3位都为0,因此相减后,就是描述符在GDT表中的索引SelectorVideo  equ LABEL_DESC_VIDEO-LABEL_GDT;END of  [SECTION .gdt][SECTION .s16][BITS 16]LABEL_BEGIN:   mov ax,cs   mov ds,ax   mov es,ax   mov ss,ax   mov sp,0100h;初始化32位代码段全局描述符的段基址   xor eax,eax   mov ax,cs   shl eax,4   add eax,LABEL_SEG_CODE32   mov word [LABEL_DESC_CODE32+2],ax   shr eax,16   mov byte [LABEL_DESC_CODE32+4],al   mov byte [LABEL_DESC_CODE32+7],ah   ;为加载GDT表做准备,先将GDT表的界限和起始地址找到存到Gdtptr中   xor eax,eax   mov ax,ds   shl eax,4   add eax,LABEL_GDT   mov dword [GdtPtr + 2],eax ;将GDT的基地址放好   lgdt  [GdtPtr]  ;将GDT表加载进来,后面可以访问GDT表中的值   ;关中断   cli   ;打开地址线A20   in al,92h   or al,00000010b   out 92h,al   ;准备切换到保护模式   mov eax,cr0   or eax,1   mov cr0,eax   ;真正进入保护模式   jmp dword SelectorCode32:0 ;执行这句话,为了将SelectorCode32                              ;指向的32为保护模式代码载入cs中                              ;并跳转到SelectorCode32:0处   ;END of  [SECTION .s16]   [SECTION .s32][BITS 32]LABEL_SEG_CODE32:   mov  ax,SelectorVideo   mov  gs,ax ;视屏段选择子加载进gs   mov  edi,(80*11 + 79)*2 ;屏幕第11行,79列   mov  ah,0Ch      ;0,为黑字,c为红字   mov  al,'P'     ;要显示的字符   mov   [gs:edi],ax   ;到此停止   jmp $       SegCode32Len equ $-LABEL_SEG_CODE32   ;END of  [SECTION .s32]

6.1)在bochs中安装Freedos

  从ttp://bochs.sourceforge.net/guestos/freedos-img.tar.gz下载Freedos包,解压后,将a.img重命名为freedos.img拷贝到当前工作目录.

6.2)用bximge命令产生一个新的映象文件pm.img(大小1.44就可以)

6.3)将bochsrc中的三行改成下面模式,保存为文件bochsrcdos

  floppya: 1_44="freedos.img", status=inserted  floppyb: 1_44="pm.img", status=inserted  boot: a

6.4)用命令bochs -f  bochsrcdos启动bochs,然后格式化b盘

如下:

6.5) 用命令nasm pmtest1dos.asm -o pmtest1.com编译出pmtest1.com文件

6.6)将pmtest1.com拷贝到虚拟软盘pm.img上

sudo mount -o loop pm.img  /mnt/floppysudo cp  pmtest1.com /mnt/floppy/sudo umount /mnt/floppy

6.7)bochs -f bochsrcdos启动后先输入6再输入c,会得到下面的界面,在界面上dos中输入b:pmtest1.com后,执行后也会输出P.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值