shineyear 发表于 2007-05-24 13:39

写了个操作系统从实模式跳转到保护模式的过程,不知道对不对

1.在一个固定地址处处创建GDT,设置堆栈积存器地址
2.读取硬盘中的load.s到0x0处
3.打开A20地址线,设置积存器PE位,进入保护模式
4.跳转到0x0处执行load.s

注:设load.s为内核程序

mik 发表于 2007-05-24 19:07

原帖由 shineyear 于 2007-5-24 13:39 发表于 1楼
1.在一个固定地址处处创建GDT,设置堆栈积存器地址
2.读取硬盘中的load.s到0x0处
3.打开A20地址线,设置积存器PE位,进入保护模式
4.跳转到0x0处执行load.s

注:设load.s为内核程序

进入保护模式之前,要先为保护模式建立必要的环境。GDT 是其中一个,另一个是 IDT

shineyear 发表于 2007-05-25 11:23

我怎么感觉IDT并不是必须的呢?

nully 发表于 2007-05-28 18:05

关了中断就可以不用idt,但这样比较无趣。

shineyear 发表于 2007-05-29 01:29

请问我可不可以在启动的时候(跳入保护模式之前)把内核加载到0X0000位置呢?我尝试着这么做了但好象不行,是不是必须关中断才行?

朱熹之 发表于 2007-05-29 08:54

在pc中,0x0000处存放中断向量表,不能加载到那里,建议先在google上搜一下bios初始化完成后的内存布局

mik 发表于 2007-05-29 18:30

原帖由 shineyear 于 2007-5-25 11:23 发表于 3楼
我怎么感觉IDT并不是必须的呢?

什么叫保护模式,要理解它的真正意义才行呀。当然,你直接将 CR0.PE 直接置 1 可以让处理器处于 Protected mode,但这样是不能正常工作的。描述符表及描述符的意义在于处理器可以提供别代码的几个该问权限级别。
从物理上来说,在 protected mode 下,执行 int 指令必须经过 IDT 该问中断例程。你的系统从来绝对不执行 INT 么?

shineyear 发表于 2007-05-29 23:05

我还是把代码贴上来吧


boot.s


.text
.globl    start
.set CODE_SEL, 0x08      
.set DATA_SEL, 0x10      
.set IDT_ADDR, 0x80000   



.set IDT_SIZE, (256*8)
.set GDT_ADDR, (IDT_ADDR+IDT_SIZE)   




.set GDT_ENTRIES, 5      



.set GDT_SIZE, (8*GDT_ENTRIES)

.set KERNEL_SECT, 2      
.set STACK_BOT, 0xa0000   





.code16
start:
      jmp      code
gdt:   
      .quad    0x0000000000000000
      .quad    0x00cf9a000000ffff
      .quad    0x00cf92000000ffff
      .quad    0x0000000000000000
      .quad    0x0000000000000000
gdt_48:
      .word    .-gdt-1
      .long    GDT_ADDR
code:
      xorw    %ax,    %ax
      movw    %ax,    %ds   
      movw    %ax,    %ss   
      movw    $0x1000,%sp   


      movw    $0x0000,%ax
      movw    %ax,    %es
      xorw    %bx,    %bx   
      movw    $KERNEL_SECT,%cx
      movw    $1,   %si   
rd_kern:
      call    read_sect   
      addw    $512,    %bx
      incw    %si
      loop    rd_kern



      cli               

      cld                  




      xorw    %ax,    %ax
      movw    %ax,    %ds   


      movw    $GDT_ADDR>>4,%ax   
      movw    %ax,    %es      
      movw    $gdt,   %si
      xorw    %di,    %di         
      movw    $GDT_SIZE>>2,%cx      
      rep
      movsl

enable_a20:      
      inb    $0x64,   %al   
      testb$0x2,    %al
      jnz    enable_a20
      movb   $0xbf,   %al
      outb   %al,   $0x64


      lgdt    gdt_48            
   
      movl   %cr0,    %eax
      orl    $0x1,    %eax
      movl   %eax,    %cr0      




      ljmp   $CODE_SEL, $0x0

read_sect:
      pushw   %ax
      pushw   %cx
      pushw   %dx
      pushw   %bx

      movw    %si,    %ax      
      xorw    %dx,    %dx
      movw    $18,    %bx   


      divw    %bx
      incw    %dx
      movb    %dl,    %cl   
      xorw    %dx,    %dx
      movw    $2,   %bx   
      divw    %bx

      movb    %dl,    %dh   
      xorb    %dl,    %dl   
      movb    %al,    %ch   

      popw    %bx         
rp_read:
      movb    $0x1,   %al   
      movb    $0x2,   %ah
      int   $0x13
      jc      rp_read
      popw    %dx
      popw    %cx
      popw    %ax
      ret


.org    0x1fe,0x90
.word   0xaa55



load.s


a.text
.globl        pm_mode
.org 0

pm_mode:
      movl    $0x10,        %eax
      movw    %ax,    %ds
      movw    %ax,    %es
      movw    %ax,    %fs
      movw    %ax,    %gs
      movw    %ax,    %ss
      movl    $0xa0000,        %esp

cld

movb    $0x07, %al
movl    $msg,%esi
movl    $0xb8000,%edi

1:
      cmp   $0,    (%esi)
        je      1f
      movsb
      stosb
      jmp   1b
1:      jmp   1b
msg:
                .string "Hello World!\x0"

shineyear 发表于 2007-05-29 23:07

我在进入保护模式之后只是让他打印了一个HELLO WORLD,没有用INT
但是我现在这段程序就是运行不起来,不知道怎么搞的

shineyear 发表于 2007-05-30 00:24

终于找到原因了,是因为我把0X0000处的BIOS中断表给覆盖了,改了加载地址和GDT地址,下面把测试通过的代码贴上来,请指教


boot.s


.text
.globl    start
.set CODE_SEL, 0x08   #选择子cs
.set DATA_SEL, 0x10       #选择子ds
.set IDT_ADDR, 0x80000    #IDT位置



.set IDT_SIZE, (256*8)
.set GDT_ADDR, (IDT_ADDR+IDT_SIZE)   #GDT位置(紧挨着IDT)




.set GDT_ENTRIES, 5      #GDT数量



.set GDT_SIZE, (8*GDT_ENTRIES)

.set KERNEL_SECT, 2      #需要读取的扇区数
.set STACK_BOT, 0xa0000   #最终的堆栈位置





.code16
start:
      jmp      code

#声明GDT
gdt:   
      .quad    0x0000000000000000
      .quad    0x00cf9a010000ffff # cs
      .quad    0x00cf92000000ffff # ds
      .quad    0x0000000000000000
      .quad    0x0000000000000000

#48位的GDT描述
gdt_48:
      .word    .-gdt-1 #长度
      .long    GDT_ADDR #位置

code:
      xorw    %ax,    %ax
      movw    %ax,    %ds   
      movw    %ax,    %ss   
      movw    $0x1000,%sp   #设置临时的堆栈位置

#将软盘中除启动扇区外的其他内容读到 es:bx处

      movw    $0x1000,%ax
      movw    %ax,    %es
      xorw    %bx,    %bx   
      movw    $KERNEL_SECT,%cx#需要读取多少扇区
      movw    $1,   %si   #跳过启动扇区
rd_kern:
      call    read_sect    #读取扇区的函数(网上找的)
      addw    $512,    %bx
      incw    %si
      loop    rd_kern



      cli               

      cld                  




      xorw    %ax,    %ax
      movw    %ax,    %ds   

#将GDT移动到指定位置
      movw    $GDT_ADDR>>4,%ax   
      movw    %ax,    %es      
      movw    $gdt,   %si
      xorw    %di,    %di         
      movw    $GDT_SIZE>>2,%cx      
      rep
      movsl


#打开A20地址线
enable_a20:      
      inb    $0x64,   %al   
      testb$0x2,    %al
      jnz    enable_a20
      movb   $0xbf,   %al
      outb   %al,   $0x64

#加载GDT
      lgdt    gdt_48      

#设置PE位      
   
      movl   %cr0,    %eax
      orl    $0x1,    %eax
      movl   %eax,    %cr0      


#跳到保护模式(跳转到了被加载的扇区位置)

      ljmp   $CODE_SEL, $0x0

read_sect:
      pushw   %ax
      pushw   %cx
      pushw   %dx
      pushw   %bx

      movw    %si,    %ax      
      xorw    %dx,    %dx
      movw    $18,    %bx   


      divw    %bx
      incw    %dx
      movb    %dl,    %cl   
      xorw    %dx,    %dx
      movw    $2,   %bx   
      divw    %bx

      movb    %dl,    %dh   
      xorb    %dl,    %dl   
      movb    %al,    %ch   

      popw    %bx         
rp_read:
      movb    $0x1,   %al   
      movb    $0x2,   %ah
      int   $0x13
      jc      rp_read
      popw    %dx
      popw    %cx
      popw    %ax
      ret


.org    0x1fe,0x90
.word   0xaa55



load.s

.text
.globl        pm_mode
.org 0

pm_mode:
        movl    $0x10,        %eax
      movw    %ax,    %ds
      movw    %ax,    %es
      movw    %ax,    %fs
      movw    %ax,    %gs
      movw    %ax,    %ss
      movl    $0xa0000,        %esp

cld

movb    $0x07, %al
movl    $msg,%esi
movl    $0xb8000,%edi

1:
      cmp   $0,    (%esi)
        je      1f
      movsb
      stosb
      jmp   1b
1:      jmp   1b
msg:
                .string "Hello World!\x0"


as -o boot.o boot.s
ld --oformat binary -N -e start -Ttext 0x7c00 -o boot.img boot.o
as -o load.o load.s
ld --oformat binary -N -e pm_mode -Ttext 0x10000 -o load.img load.o
cat boot.img load.img > final.img

用VMWARE加载 final.img 即可

[ 本帖最后由 shineyear 于 2007-5-30 11:13 编辑 ]
页: [1] 2
查看完整版本: 写了个操作系统从实模式跳转到保护模式的过程,不知道对不对