QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1552|回复: 12

进入保护模式的程序,可惜是要大家帮忙给看看什么地方出错了

[复制链接]
发表于 2003-6-26 16:35:10 | 显示全部楼层 |阅读模式
原程序
[code:1]
#define        CR0_PE                1

        .text
        .code16
        .globl _start
_start:
        jmp  start0
        nop  
mesg1:
        .ascii "Loading......       "
mesg2:
        .ascii "Ready........       "
##################### idt ########################
idt:
        .word   0
        .word   0, 0
##################### gdt ########################
        .align  16
gdt:
        .word        0, 0
        .byte        0, 0x00, 0x00, 0
bootcodeseg = . - gdt
        .word        0xffff, 0
        .byte        0, 0x9e, 0x4f, 0
bootdataseg = . - gdt
        .word        0xffff, 0
        .byte        0, 0x92, 0x4f, 0
videoseg    = . - gdt
        .word 0x3999, 0x8000
        .byte 0x0b, 0x92, 0x00, 0x00
bootrealseg = . - gdt
        .word        0xffff, 0
        .byte        0, 0x9e, 0x00, 0
bootrealdata = . - gdt
        .word        0xffff, 0
        .byte        0, 0x92, 0x00, 0
gdtlen = . - gdt
        .align        16
gdtarg:
        .word        gdtlen-1                /* limit */
        .long        0                        /* physical addr, will be inserted */
ourseg:        .word        0                        /* real mode code and data segment */
stkseg:        .word        0                        /* real mode stack segment */
stkdif:        .long        0                        /* diff. between real and prot sp */
#
# start of code
#
start0:
        mov        %cs, %ax                /* don't trust values of ds, es or ss */
        mov        %ax, %ds
        mov        %ax, %es
        mov        %ax, %ss
        mov        $0xfffc, %sp

        xor        %ax, %ax                /* in particular ah = 0 */
        int        $0x13

        call    clrscr
        movw    $mesg1,%bp
        call    prt_msg
        call    get_key
        call    clrscr
        call    gdt_fixup
        movw    $mesg2,%bp
        call    prt_msg
        call    get_key
        call    clrscr
        call    real_to_prot
loop:
        jmp loop
gdt_fixup:
        .code16
        pushw        %ax
        pushw        %dx

        xorl        %eax, %eax
        mov        %cs, %ax
        mov        %ax, ourseg
        /* sort out stuff for %ss != %ds */
        movw        %ss, %dx
        movw        %dx, stkseg
        subw        %ax, %dx
        shll        $16, %edx
        shrl        $12, %edx
        movl        %edx, stkdif

        /* fix up GDT entries for bootstrap */
        mov        %ax, %dx
        shll        $4, %eax
        shr        $12, %dx

#define FIXUP(gdt_index)              \
        movw        %ax, gdt+gdt_index+2; \
        movb        %dl, gdt+gdt_index+4

        FIXUP(bootcodeseg)
        FIXUP(bootrealseg)
        FIXUP(bootdataseg)

        /* fix up GDT pointer */
        addl        $gdt, %eax
        movl        %eax, gdtarg+2       
       
        pop        %dx
        pop        %ax
        ret

real_to_prot:
        .code16
        pushl        %eax
        cli

        lidt        %cs:idt
        lgdt        %cs:gdtarg                /* Global descriptor table */

        movl        %cr0, %eax
        or        $CR0_PE, %ax
        movl        %eax, %cr0                 /* Enter 'protected mode' */
        ljmp        $bootcodeseg, $1f        /* Jump into a 32bit segment */
1:
        .code32
dbg:
        jmp     dbg
        /*  Set all the segment registers to map the same area as the code */
        mov        $bootdataseg, %eax
        mov        %ax, %ds
        mov        %ax, %es
        mov        %ax, %ss
        addl        stkdif, %esp                /* Allow for real %ss != %ds */
       
        mov     $videoseg, %eax
        mov     %ax, %gs
        movw    $0x741,0x000b8000
spin:
        jmp     spin
        popl        %eax
        ret

prt_msg:
        .code16
        movb $0x13,%ah
        movb $0x00,%al
        movw $0x0007,%bx
        movw $0x14,%cx
        movw $0x0000,%dx
        int  $0x10
        ret
get_key:
        .code16
        movb   $0x00,%ah
        int    $0x16
        ret
clrscr:
        .code16
        movw $0x0600,%ax
        movw $0x0000,%cx
        movw $0x174f,%dx
        movb $0x0,   %bh
        int  $0x10
        ret


        .org 510
boot_flag:
        .word 0xAA55

[/code:1]

make文件
[code:1]
boot : bootp.out
        objcopy -S -O binary bootp.out boot
bootp.out : bootp.o
        ld -nostdlib -static -N -e _start -Ttext 0x7c00 -o bootp.out bootp.o
bootp.o : _bootp.S
        as -o bootp.o _bootp.S
_bootp.S : bootp.S
        cc -o _bootp.S -E bootp.S
clean :
        rm -rf bootp.o bootp.out _bootp.S
install :
        dd bs=512 if=boot of=/dev/fd0

[/code:1]
功能:
启动,打印字符串,按任意键继续,最后在保护模式下显示一个A

问题:
我在ljmp下放了一条死循环,用来debug,因为一进行跳转系统就重启。

使用方法:
make  编译
make clean 删除中间文件
make install 写入软盘

那位精通一块研究一下啊,特别是两位斑竹...
发表于 2003-6-27 03:46:22 | 显示全部楼层
sorry, no idea on this. i am poor at asm code.

can jjww try this?  
回复

使用道具 举报

发表于 2003-6-27 11:58:06 | 显示全部楼层

我也比较弱。我想我没有时间做测试。你有什么问题,是什么方面看不懂,说具体点,我们一起讨论。
回复

使用道具 举报

发表于 2003-6-27 13:04:02 | 显示全部楼层
movw    $0x741,0x000b8000
这句话有点迷惑,和普通BIOS显示中断调用(int)不一样,
不知道显卡的BIOS调用什么规范的,我想这就是打印的‘A’的意思吧。不知道猜对没?
回复

使用道具 举报

发表于 2003-6-27 23:31:55 | 显示全部楼层
我用的djgpp,去掉了gdt_fixup我觉得没必要

#define   CR0_PE      1

   .text
   .code16
   .globl _start
_start:
   jmp  start0
   nop  
mesg1:
   .ascii "Loading......       "
mesg2:
   .ascii "Ready........       "
##################### idt ########################
idt:
   .word   0
   .word   0, 0
##################### gdt ########################
#   .align  16
gdt:
   .word   0, 0
   .byte   0, 0x00, 0x00, 0
bootcodeseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x9e, 0x4f, 0
bootdataseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x92, 0x4f, 0
videoseg    = . - gdt
   .word 0x3999, 0x8000
   .byte 0x0b, 0x92, 0x00, 0x00
bootrealseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x9e, 0x00, 0
bootrealdata = . - gdt
   .word   0xffff, 0
   .byte   0, 0x92, 0x00, 0
gdtlen = . - gdt
#   .align   16
gdtarg:
   .word   gdtlen-1      /* limit */
   .long   gdt         /* physical addr, will be inserted */
ourseg:   .word   0         /* real mode code and data segment */
stkseg:   .word   0         /* real mode stack segment */
stkdif:   .long   0         /* diff. between real and prot sp */
#
# start of code
#
start0:
   mov   %cs, %ax      /* don't trust values of ds, es or ss */
   mov   %ax, %ds
   mov   %ax, %es
   mov   %ax, %ss
   mov   $0xfffc, %sp

   xor   %ax, %ax      /* in particular ah = 0 */
   int   $0x13

   call    clrscr
   movw    $mesg1,%bp
   call    prt_msg
   call    get_key
   call    clrscr
#   call    gdt_fixup
   movw    $mesg2,%bp
   call    prt_msg
   call    get_key
   call    clrscr
   call    real_to_prot
loop:
   jmp loop

real_to_prot:
   .code16
   pushl   %eax
   cli

   lidt   idt
   lgdt   gdtarg      /* Global descriptor table */

   movl   %cr0, %eax
   or     $0x1, %al
   movl   %eax, %cr0       /* Enter 'protected mode' */
   ljmp   $bootcodeseg, $1f   /* Jump into a 32bit segment */
1:
   .code32
   /*  Set all the segment registers to map the same area as the code */
   mov   $bootdataseg, %eax
   mov   %ax, %ds
   mov   %ax, %es
   mov   %ax, %ss
   addl   stkdif, %esp      /* Allow for real %ss != %ds */
   
   mov     $videoseg, %eax
   mov     %ax, %gs
   movw    $0x741,0x000b8000
spin:
   jmp     spin
   popl   %eax
   ret

prt_msg:
   .code16
   movb $0x13,%ah
   movb $0x00,%al
   movw $0x0007,%bx
   movw $0x14,%cx
   movw $0x0000,%dx
   int  $0x10
   ret
get_key:
   .code16
   movb   $0x00,%ah
   int    $0x16
   ret
clrscr:
   .code16
   movw $0x0600,%ax
   movw $0x0000,%cx
   movw $0x174f,%dx
   movb $0x0,   %bh
   int  $0x10
   ret


   .org 510
boot_flag:
   .word 0xAA55
回复

使用道具 举报

 楼主| 发表于 2003-6-28 22:41:14 | 显示全部楼层
不好意思,各位,其实昨天已经弄好了,只是一直看租来的连续剧,一口气看了20多集,刚刚睡醒,呵呵。
to jjww
0x000b8000是显存的位置,也许在缺省的图形模式可以直接使用,pc的资料太古怪太枯燥了,看得人好烦,各种资料的解释只有一个,为了照顾向下兼容才有这么许多古里古怪的内容,有的时候觉得反正现在也没有人再用,还留着他们干嘛

to tielian
谢谢你一块调程序,gdt_fixup是不能删的,因为这个过程才是初始化gdt表的内容
我简单解释一下

在保护模式下,gdt表里一项是8个字节,其中的第3,4,5,8组成一个段的32位基地址。进入保护模式之前,要把一个6字节的内容装载到gdtr寄存器里说明gdt表的基地址,表长和属性,程序里把它保存到了gdtarg里。gdt_fixup的功能就是把实模式下的各段地址写到gdt表里去并为gdtarg设置真正的值。

好像是我对sp的初始化有问题,所以我把它删了就没事了,改进后的程序如下:
[code:1]
#define   CR0_PE      1

   .text
   .code16
   .globl _start
_start:
   jmp  start0
   nop  
mesg1:
   .ascii "Loading......       "
mesg2:
   .ascii "Ready........       "
##################### idt ########################
idt:
   .word   0
   .word   0, 0
##################### gdt ########################
   .align  16
gdt:
   .word   0, 0
   .byte   0, 0x00, 0x00, 0
bootcodeseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x9e, 0x4f, 0
bootdataseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x92, 0x4f, 0
videoseg    = . - gdt
   .word 0x3999, 0x8000
   .byte 0x0b, 0x92, 0x00, 0x00
bootrealseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x9e, 0x00, 0
bootrealdata = . - gdt
   .word   0xffff, 0
   .byte   0, 0x92, 0x00, 0
gdtlen = . - gdt
   .align   16
gdtarg:
   .word   gdtlen-1      /* limit */
   .long   0         /* physical addr, will be inserted */
ourseg:   .word   0         /* real mode code and data segment */
stkseg:   .word   0         /* real mode stack segment */
stkdif:   .long   0         /* diff. between real and prot sp */
#
# start of code
#
start0:
   mov   %cs, %ax      /* don't trust values of ds, es or ss */
   mov   %ax, %ds
   mov   %ax, %es
   mov   %ax, %ss
#   mov   $0xfffc, %sp

   xor   %ax, %ax      /* in particular ah = 0 */
   int   $0x13

   call    clrscr
   movw    $mesg1,%bp
   call    prt_msg
   call    get_key
   call    clrscr
   call    gdt_fixup
   movw    $mesg2,%bp
   call    prt_msg
   call    get_key
   call    clrscr
   call    real_to_prot
loop:
   jmp loop
gdt_fixup:
   .code16
   pushw   %ax
   pushw   %dx

   xorl   %eax, %eax
   mov   %cs, %ax
   mov   %ax, ourseg
   /* sort out stuff for %ss != %ds */
   movw   %ss, %dx
   movw   %dx, stkseg
   subw   %ax, %dx
   shll   $16, %edx
   shrl   $12, %edx
   movl   %edx, stkdif

   /* fix up GDT entries for bootstrap */
   mov   %ax, %dx
   shll   $4, %eax
   shr   $12, %dx

#define FIXUP(gdt_index)              \
   movw   %ax, gdt+gdt_index+2; \
   movb   %dl, gdt+gdt_index+4

   FIXUP(bootcodeseg)
   FIXUP(bootrealseg)
   FIXUP(bootdataseg)

   /* fix up GDT pointer */
   addl   $gdt, %eax
   movl   %eax, gdtarg+2   
   
   pop   %dx
   pop   %ax
   ret

real_to_prot:
   .code16
   pushl   %eax
   cli

   lidt   %cs:idt
   lgdt   %cs:gdtarg      /* Global descriptor table */

   movl   %cr0, %eax
   or   $CR0_PE, %ax
   movl   %eax, %cr0       /* Enter 'protected mode' */
   ljmp   $bootcodeseg, $1f   /* Jump into a 32bit segment */
1:
   .code32
dbg:
   jmp     dbg
   /*  Set all the segment registers to map the same area as the code */
   mov   $bootdataseg, %eax
   mov   %ax, %ds
   mov   %ax, %es
   mov   %ax, %ss
   addl   stkdif, %esp      /* Allow for real %ss != %ds */
   
   mov     $videoseg, %eax
   mov     %ax, %gs
   movw    $0x741,%gs:0
spin:
   jmp     spin
   popl   %eax
   ret

prt_msg:
   .code16
   movb $0x13,%ah
   movb $0x00,%al
   movw $0x0007,%bx
   movw $0x14,%cx
   movw $0x0000,%dx
   int  $0x10
   ret
get_key:
   .code16
   movb   $0x00,%ah
   int    $0x16
   ret
clrscr:
   .code16
   movw $0x0600,%ax
   movw $0x0000,%cx
   movw $0x174f,%dx
   movb $0x0,   %bh
   int  $0x10
   ret


   .org 510
boot_flag:
   .word 0xAA55

[/code:1]

因为我是使用
movw    $0x741,%gs:0
这段代码来写显存,所以应该认为是使用的保护模式
回复

使用道具 举报

发表于 2003-6-28 22:51:59 | 显示全部楼层
呵呵,你应该没看到我以经将gdtr初始化了吧
gdtarg:
.word gdtlen-1 /* limit */
.long   gdt       /* physical addr, will be inserted */
回复

使用道具 举报

 楼主| 发表于 2003-6-28 23:04:27 | 显示全部楼层
sorry,不好意思,没仔细看
但是gdt表的内容还没有初始化,尤其是
[code:1]
bootcodeseg = . - gdt
   .word   0xffff, 0
   .byte   0, 0x9e, 0x4f, 0
[/code:1]
这一段,没有填值,填完以后应该是
[code:1]
bootcodeseg = . - gdt
   .word   0xffff, 0x000c
   .byte   0007, 0x9e, 0x4f, 0
[/code:1]

你编译的程序可以运行吗?
回复

使用道具 举报

发表于 2003-6-29 01:20:01 | 显示全部楼层
我先问你个问题,在你这个程序中cs=?如果你知道了,就明白
这个是错误的

bootcodeseg = . - gdt
   .word   0xffff, 0x000c
   .byte   0007, 0x9e, 0x4f, 0
回复

使用道具 举报

 楼主| 发表于 2003-6-29 15:10:16 | 显示全部楼层
cs的值是0x7c00,因为那个长跳转是使用bootcodeseg里的数据进行的,所以在ljmp之前不往bootcodeseg里填入正确的值是会出错的,那个宏FIXUP就是要把cs的值正确填入gdt里的各个描述符里。
回复

使用道具 举报

发表于 2003-6-29 15:16:23 | 显示全部楼层
cs=0x0!
你可以自行验正。
bios将boot sector装载到0:0x7c00!
回复

使用道具 举报

 楼主| 发表于 2003-6-29 15:24:16 | 显示全部楼层
不好意思,是我搞错了,初始化时是ip的值是7c00.

在这个程序里,使用fixup函数确实是多此一举,呵呵
回复

使用道具 举报

发表于 2003-7-7 19:51:02 | 显示全部楼层
强,不过我还暂时看不懂
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-16 09:45 , Processed in 0.041060 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表