Page 1 of 1
problems entering protected mode
Posted: Sat Nov 11, 2006 8:29 am
by Seven11
My second bootloader is loaded from a FAT12 disk by the bootsector to the addr 10000h and it uses this code:
Code: Select all
cli
o32 lgdt[gdtr]
o32 lidt[idtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp code32sel:pmode
bits32
pmode:
jmp $
To get into pmode, this code has always worked but now when I changed the bootloader addr from 7e00h (right after the bootsector) to 10000h it stopped working. Also I can say that all the segments are cleared before running the above code except CS which is 1000h.
Also, bochs tells me this:
"fetch_raw_descriptor: GDT: index (f)1 > limit (0)"
Looking at the NASM output for the lgdt and lidt instructions:
000023A2 660F0116[D621] o32 lgdt[gdtr]
000023A8 660F011E[F421] o32 lidt[idtr]
makes me think that the cpu never get's the GDT or IDT table since they are located att addr 121D6h (GDT) and 121F4h (IDT)...
any good solutions?
Re: problems entering protected mode
Posted: Sat Nov 11, 2006 8:53 am
by Brendan
Hi,
Which assembler are you using, what do you use for "ORG", what is in DS when this code is run and what data is at gdtr and idtr?
Cheers,
Brendan
Posted: Sat Nov 11, 2006 8:57 am
by Dex
First are you setting any org in your second stage and if so, what is it ?
Next bubach had a problem like this, with BOS have a look at that code to see how he fixed it.
http://bos.asmhackers.net/downloads.php
I think he had to do something like this:
Code: Select all
lgdt [gdtr - 0x10000] ; Load the GDT descriptor
lidt [idtr - 0x10000] ; Load the IDT descriptor
PS: Whats the "o32" ?
Posted: Sat Nov 11, 2006 10:25 am
by Seven11
brendan: as I wrote, the base addr och the bootloader is 10000h and "all the segments are cleared before running the above code except CS which is 1000h." => DS = 0. The assembler is NASM.
Dex: "o32" tells NASM to use 32-bits operand (in other words adding the instruction prefix 66h), look in the Instruction Set Reference from Intel on the instruction "LGDT/LIDT".
The GDT table looks like this:
Code: Select all
%macro GDT_ENTRY 6
%%LIMIT_15_0 dw %1
%%BASE_15_0 dw %2
%%BASE_23_16 db %3
%%OPT_1 db %4
%%OPT_2_LIMIT_19_16 db %5
%%BASE_31_24 db %6
%endmacro
gdtr
dw gdt_end-gdt-1
dd gdt
gdt
nullseg equ ($-gdt)
GDT_ENTRY 0h, 0h, 0h, 0h, 0h, 0h ;nullseg
code32sel equ ($-gdt)
GDT_ENTRY 0FFFFh, 0h, 0h, 9ah, 0cfh, 0h ;Kernel Code
data32sel equ ($-gdt)
GDT_ENTRY 0FFFFh, 0h, 0h, 92h, 0cfh, 0h ;Kernel
gdt_end
PS! I have removed the "lidt" instruction for now to make debugging easier, it will be added again when the lgdt thing works.
PS #2! BOS seems to be entering Pmode in the bootsector, this is not an option for me because the bootloader probes the BIOS for VESA, APM and Memory information...
One last option is to move back the bootloader to under the 10000h mark, but shouldn't it be possible to get into Pmode when your above 10000h???
Posted: Sat Nov 11, 2006 10:58 am
by Brendan
Hi,
Seven11 wrote:brendan: as I wrote, the base addr och the bootloader is 10000h and "all the segments are cleared before running the above code except CS which is 1000h." => DS = 0. The assembler is NASM.
The "o32" will change the operand size, but won't change the address size. To do that you'd need:
Code: Select all
o32 lgdt [dword gdtr] ; Load the GDT descriptor
In this case, NASM should generate an "o32 lgdt [0x0001????] instruction, which is what you want (because DS base is zero), but will also cause a general protection fault (because the address is above the 64 KB limit for DS).
To fix this, either:
Code: Select all
mov ax,0x1000
mov ds,ax
o32 lgdt [gdtr] ; Load the GDT descriptor
Or perhaps:
Code: Select all
o32 lgdt [cs:gdtr] ; Load the GDT descriptor
You should also have a problem with your far jump, which probably needs to be:
Cheers,
Brendan
Posted: Sat Nov 11, 2006 11:07 am
by Seven11
for some reason:
Code: Select all
o32 lgdt [dword gdtr] ; Load the GDT descriptor
doesn't work... however...
did it
so If anybody else has the problem here is the code to solve it:
Code: Select all
;Enter Pmode from above 10000h
cli
o32 lgdt[gdtr] ;assumes BASE(DS)*16+gdtr points to GDT structure.
o32 lgdt[idtr] ;BASE(DS)*16+idtr should point to the IDT structure.
mov eax,cr0
or al,1
mov cr0,eax
jmp dword code32sel:pmode ;where "code32sel" is your 32-bit kernel code seg.
bits 32
pmode:
mov ax,data32sel ;where "data32sel" is your 32-bit kernel data seg.
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
Thanks for the help!