Protected Mode Troubles
Posted: Sat Apr 24, 2004 2:09 pm
I'm attempting to write a bootsector that will enable the A20 line and then throw protected mode up. It's been a few days now and I still cannot find what error is causing my pmode enabling section to fail. I'm using Bochs on FreeBSD for testing. It appears anytime I try to enable the PE flags in cr0 the machine resets. I'm assuming it's some problem with my GDTR or GDT but I cannot find the error. Here is the assembly code I'm working off:
.set SEL_CODE, 0x8
.set SEL_LINEAR, 0x10
.org 0x000
.code16
ljmp $0x7C0, $start # far jump to load the CS with known value
# some BIOS' start at 07c0:0000 and others
# at 0000:7c00
.globl start
start:
movw $0x7C0, %ax # load known address
movw %ax, %ds # into the segment
movw %ax, %es # registers.
movw %ax, %fs
movw %ax, %gs
xorw %ax, %ax # setup
movw %ax, %ss # ... the
movw $0xffff, %sp # ... stack
movw $bootmessage, %si # put something
call putstr # on the screen
call gateA20 # enable the A20 line
pushw $0x2
popf
lgdt (gdt_ptr+0x7C00) # Initialize GDTR, need a linear address
# not a segmented one.
movl %cr0, %eax
orb $0x1, %al
movl %eax, %cr0
ljmp $SEL_CODE, $pmode # long jump to reload %cs
gateA20:
push %si
push %ax
movw $A20Message, %si
call putstr
inb $0x92, %al
orb $0x02, %al
outb %al, $0x92
pop %ax
pop %si
ret
putstr:
push %ax
push %bx
movb $0x0e, %ah
movw $0x0007, %bx
putstr.0:
lodsb
testb %al, %al
jz putstr.1
int $0x10
jmp putstr.0
putstr.1:
pop %bx
pop %ax
ret
.code32
pmode:
jmp .
# Enter protected mode
bootmessage: .asciz "SOS Bootloader (v.01)\n"
A20Message: .asciz "Enabling A20 line...\n"
pmodemsg: .asciz "Jumping to PMode...\n"
# GDT
# Segment Descriptor Layout:
#
# 31 24 23 22 21 20 19 16 15 14 13 12 11 8 7 0 Byte
# _________________________________________________________________________
# | | |D | |A | Seg | | D | | | |
# | Base 31:24 |G |/ |O |V | Limit |P | P |S | Type | Base 23:16| 4
# | | |B | |L | 19:16 | | L | | | |
# |___________________|__|__|__|__|________|__|_____|__|________|___________|
#
# 31 16 15 0
# _________________________________________________________________________
# | | |
# | Base Address 15:00 | Segment Limit 15:00 | 0
# |________________________________________|________________________________|
.org 0x0120
gdt_ptr: .word gdt_end-gdt-1
.word (gdt+0x7C00)
.byte 0x0
gdt:
gdt.0: # Null selector
.word 0 # [Off. 0] Segment Limit (15:00)
.word 0 # [Off. 2] Base Address (15:00)
.byte 0 # [Off. 4] Base Address (23:16)
.byte 0 # [Off. 5] Flags
.byte 0 # [Off. 6] Seg Limit & Flags
.byte 0 # [Off. 7] Base Address (31:24)
gdt.1: # Code (0x7C00 base)
.word 0xFFFF # [Off. 0] Segment Limit (15:00)
.word 0x7C00 # [Off. 2] Base Address (15:00)
.byte 0x00 # [Off. 4] Base Address (23:16)
.byte 0x9A # [Off. 5] Flags
.byte 0xCF # [Off. 6] Seg Limit & Flags
.byte 0x00 # [Off. 7] Base Address (31:24)
gdt.2: # Linear (0x0 base)
.word 0xFFFF # [Off. 0] Segment Limit (15:00)
.word 0x0 # [Off. 2] Base Address (15:00)
.byte 0x0 # [Off. 4] Base Address (23:16)
.byte 0x92 # [Off. 5] Flags
.byte 0xCF # [Off. 6] Seg Limit & Flags
.byte 0x0 # [Off. 7] Base Address (31:24)
gdt_end:
.org 0x01fe
.word 0xaa55
Any help would be greatly appreciated.
.set SEL_CODE, 0x8
.set SEL_LINEAR, 0x10
.org 0x000
.code16
ljmp $0x7C0, $start # far jump to load the CS with known value
# some BIOS' start at 07c0:0000 and others
# at 0000:7c00
.globl start
start:
movw $0x7C0, %ax # load known address
movw %ax, %ds # into the segment
movw %ax, %es # registers.
movw %ax, %fs
movw %ax, %gs
xorw %ax, %ax # setup
movw %ax, %ss # ... the
movw $0xffff, %sp # ... stack
movw $bootmessage, %si # put something
call putstr # on the screen
call gateA20 # enable the A20 line
pushw $0x2
popf
lgdt (gdt_ptr+0x7C00) # Initialize GDTR, need a linear address
# not a segmented one.
movl %cr0, %eax
orb $0x1, %al
movl %eax, %cr0
ljmp $SEL_CODE, $pmode # long jump to reload %cs
gateA20:
push %si
push %ax
movw $A20Message, %si
call putstr
inb $0x92, %al
orb $0x02, %al
outb %al, $0x92
pop %ax
pop %si
ret
putstr:
push %ax
push %bx
movb $0x0e, %ah
movw $0x0007, %bx
putstr.0:
lodsb
testb %al, %al
jz putstr.1
int $0x10
jmp putstr.0
putstr.1:
pop %bx
pop %ax
ret
.code32
pmode:
jmp .
# Enter protected mode
bootmessage: .asciz "SOS Bootloader (v.01)\n"
A20Message: .asciz "Enabling A20 line...\n"
pmodemsg: .asciz "Jumping to PMode...\n"
# GDT
# Segment Descriptor Layout:
#
# 31 24 23 22 21 20 19 16 15 14 13 12 11 8 7 0 Byte
# _________________________________________________________________________
# | | |D | |A | Seg | | D | | | |
# | Base 31:24 |G |/ |O |V | Limit |P | P |S | Type | Base 23:16| 4
# | | |B | |L | 19:16 | | L | | | |
# |___________________|__|__|__|__|________|__|_____|__|________|___________|
#
# 31 16 15 0
# _________________________________________________________________________
# | | |
# | Base Address 15:00 | Segment Limit 15:00 | 0
# |________________________________________|________________________________|
.org 0x0120
gdt_ptr: .word gdt_end-gdt-1
.word (gdt+0x7C00)
.byte 0x0
gdt:
gdt.0: # Null selector
.word 0 # [Off. 0] Segment Limit (15:00)
.word 0 # [Off. 2] Base Address (15:00)
.byte 0 # [Off. 4] Base Address (23:16)
.byte 0 # [Off. 5] Flags
.byte 0 # [Off. 6] Seg Limit & Flags
.byte 0 # [Off. 7] Base Address (31:24)
gdt.1: # Code (0x7C00 base)
.word 0xFFFF # [Off. 0] Segment Limit (15:00)
.word 0x7C00 # [Off. 2] Base Address (15:00)
.byte 0x00 # [Off. 4] Base Address (23:16)
.byte 0x9A # [Off. 5] Flags
.byte 0xCF # [Off. 6] Seg Limit & Flags
.byte 0x00 # [Off. 7] Base Address (31:24)
gdt.2: # Linear (0x0 base)
.word 0xFFFF # [Off. 0] Segment Limit (15:00)
.word 0x0 # [Off. 2] Base Address (15:00)
.byte 0x0 # [Off. 4] Base Address (23:16)
.byte 0x92 # [Off. 5] Flags
.byte 0xCF # [Off. 6] Seg Limit & Flags
.byte 0x0 # [Off. 7] Base Address (31:24)
gdt_end:
.org 0x01fe
.word 0xaa55
Any help would be greatly appreciated.