写了个操作系统从实模式跳转到保护模式的过程,不知道对不对
1.在一个固定地址处处创建GDT,设置堆栈积存器地址2.读取硬盘中的load.s到0x0处
3.打开A20地址线,设置积存器PE位,进入保护模式
4.跳转到0x0处执行load.s
注:设load.s为内核程序 原帖由 shineyear 于 2007-5-24 13:39 发表于 1楼
1.在一个固定地址处处创建GDT,设置堆栈积存器地址
2.读取硬盘中的load.s到0x0处
3.打开A20地址线,设置积存器PE位,进入保护模式
4.跳转到0x0处执行load.s
注:设load.s为内核程序
进入保护模式之前,要先为保护模式建立必要的环境。GDT 是其中一个,另一个是 IDT 我怎么感觉IDT并不是必须的呢? 关了中断就可以不用idt,但这样比较无趣。 请问我可不可以在启动的时候(跳入保护模式之前)把内核加载到0X0000位置呢?我尝试着这么做了但好象不行,是不是必须关中断才行? 在pc中,0x0000处存放中断向量表,不能加载到那里,建议先在google上搜一下bios初始化完成后的内存布局 原帖由 shineyear 于 2007-5-25 11:23 发表于 3楼
我怎么感觉IDT并不是必须的呢?
什么叫保护模式,要理解它的真正意义才行呀。当然,你直接将 CR0.PE 直接置 1 可以让处理器处于 Protected mode,但这样是不能正常工作的。描述符表及描述符的意义在于处理器可以提供别代码的几个该问权限级别。
从物理上来说,在 protected mode 下,执行 int 指令必须经过 IDT 该问中断例程。你的系统从来绝对不执行 INT 么? 我还是把代码贴上来吧
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" 我在进入保护模式之后只是让他打印了一个HELLO WORLD,没有用INT
但是我现在这段程序就是运行不起来,不知道怎么搞的 终于找到原因了,是因为我把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