Switching to protected

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
jesperlp

Switching to protected

Post 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
carbonBased

RE:Switching to protected

Post 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?
jesperlp

RE:Switching to protected

Post 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
jesperlp

RE:Switching to protected

Post 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
carbonBased

RE:Switching to protected

Post 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
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

RE:Switching to protected

Post 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.
-- Stu --
carbonBased

RE:Switching to protected

Post 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
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

RE:Switching to protected

Post by df »

your right, it just seems really odd to load  24bit base + 16bit limit.. whats the point?? bizarre :) ohwell.
-- Stu --
Tim Robinson

RE:Switching to protected

Post 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. :)
Post Reply