Page 1 of 1
Switching to protected
Posted: Fri May 09, 2003 11:00 pm
by jesperlp
Hi all
I'm trying to switch to protected mode right after the system has booted but I can't seem to get it right. No matter what I do my computer just reboots whenever I try to access some memory.
I'm going to post my code because I have no more ideas to what might be wrong with it. It is written in NASM. The program is put in sector 0 on a floppy disk when I try it out, which works perfectly fine in real mode but not when I try to switch to pm.
Anyway here's my code:
cli
xor eax,eax ; segment descriptors address
mov ax,cs
shl eax,4
add eax,desc
mov [gdtraddr],eax
db 66h ; 32 bit lgdt
lgdt [gdtr]
mov eax,cr0 ; protected mode
or eax,1 ; PE bit
mov cr0,eax
;jmp clearpq ; clear prefetch queue
db 0eah
dw clearpq+7c00h
dw 8
clearpq:
mov ax,16
mov ds,ax
mov al,'a'
mov [DWORD 0b8000h],al
a:
jmp a
gdtr: ; gdtr
gdtrlimit dw 23
gdtraddr dd 0
desc: ; segment descriptors
nulllow dd 0
nullhigh dd 0
codelinlow dd 00000000000000001111111111111111b
codelinhigh dd 00000000110011111001101000000000b
datalinlow dd 00000000000000001111111111111111b
datalinhigh dd 00000000110011111001001000000000b
RE:Switching to protected
Posted: Fri May 09, 2003 11:00 pm
by carbonBased
A few things, that might help:
First of all, you seem to be assuming what CS is set to upon boot-up... to be safe, I'd set CS before performing any operations.
Secondly, you've set gdtraddr = cs * 16 + desc
I believe you're looking for cs * 16 + desc + 0x7c00
And finally, I haven't looked through your GDT, I'm simply assuming you've set both the code and data segments to be 4GB linear, starting at 0 (anything other then 0, and your code wont work).
Jeff
PS: Are you sure lgdt accepts the 0x66 prefix?
RE:Switching to protected
Posted: Sat May 10, 2003 11:00 pm
by jesperlp
Hi Jeff,
thanks for looking at my code.
I thought that a computer starts executing the os at 07c0:000 and because of that you could be sure that cs is 7c0h. But I'm gonna let my program print out cs and ip just to see what's really in them.
If cs is 7c0h shouldn't gdtaddr be set to cs*16+desc. The physical address is calculated by segment*16+offset or did I get this wrong?
About the 66h prefix, I got this from an mode switching example in one of Intel's manuals. I doesn't really say why they use it.
Anyway thanks for your help,
Jesper
RE:Switching to protected
Posted: Sat May 10, 2003 11:00 pm
by jesperlp
Hey,
I just got my code working.
My computer starts executing at 0000:7c00 not 07c0:0000 so I made a few changes in my code which now looks like this:
call 7c0h:5 ; set cs to 7c0h and jump to next instruction
cli
mov ax,cs ; set ds to cs
mov ds,ax
mov eax,7c00h ; segment descriptors adresse
add eax,desc
mov [gdtraddr],eax
db 66h ; 32 bit lgdt
lgdt [gdtr]
mov eax,cr0 ; protected mode
or eax,1 ; PE bit
mov cr0,eax
;jmp clearpq ; clear prefetch queue
db 0eah
dw clearpq+7c00h
dw 8
clearpq:
BITS 32
mov ax,16
mov ds,ax
mov al,'a'
mov [0b8000h],al
a:
jmp a
; data
gdtr: ; gdtr
gdtrlimit dw 23
gdtraddr dd 0
desc: ; segment descriptors
nulllow dd 0
nullhigh dd 0
codelinlow dd 00000000000000001111111111111111b
codelinhigh dd 00000000110011111001101000000000b
datalinlow dd 00000000000000001111111111111111b
datalinhigh dd 00000000110011111001001000000000b
By the way I found out that doing a 32 bit lgdt means that it loads a 32 bit address where a 16 bit lgdt would only load a 24 bit address.
Thanks again for your help,
Jesper
RE:Switching to protected
Posted: Sat May 10, 2003 11:00 pm
by carbonBased
Yeah, that's what I figured; both 0000:7c00 and 07c0:0000 are exactly equivalent, so it's definitly not portable to assume the BIOS sets cs to 7C0. Some probably do, others may not.
And yes, 0x66 and 0x67 override prefixes.
0x66 = operand-size override
0x67 = address-size override
It just seemed odd to have the prefix, but then, I always forget that you can, in fact, lgdt in real mode; it's just... no one really does
Anyway, good to hear that it works,
Jeff
RE:Switching to protected
Posted: Sun May 11, 2003 11:00 pm
by df
----
By the way I found out that doing a 32 bit lgdt means that it loads a 32 bit address where a 16 bit lgdt would only load a 24 bit address.
---
is your assumption still correct? an lgdt in realmode will still load a 32bit address.. iirc, the 24bit address only applies on a 286, doing it on a 386+ will elict a 32bit address.
RE:Switching to protected
Posted: Mon May 12, 2003 11:00 pm
by carbonBased
Well, apparently some people need clarification on lgdt;
If given a 16-bit operand (ie, program is typically running in real mode), it will load a 24-bit base and a 16-bit limit (the high-order eight bits of the six-byte data operand is not used)
If given a 32-bit operand (ie, programming is typically running in pmode), it will load a 32-bit base, and a 16-bit limit (remember, this limit can be in 4kb or 4MB pages).
Cheers,
Jeff
RE:Switching to protected
Posted: Mon May 12, 2003 11:00 pm
by df
your right, it just seems really odd to load 24bit base + 16bit limit.. whats the point?? bizarre
ohwell.
RE:Switching to protected
Posted: Tue May 13, 2003 11:00 pm
by Tim Robinson
Same point as most of IA-32's other bizzare points: to keep compatibility with all those 16-bit protected mode programs.