Page 1 of 4
can't re-enter realmode
Posted: Tue Apr 06, 2004 7:49 am
by ich_will
I try to re-enter realmode so I can shutdown my PC (Power Off), but the cpu triple faults
Code: Select all
__shutdown:
cli ; disable interrupts
;------ clear the PG bit ------
mov eax, cr0
xor eax, 0x80000000
mov cr0, eax
;------ clear the paging cache ------
xor eax, eax
mov cr3, eax
;------ do a far jump to a 16-bit code segment ------
jmp dword real_mode
[BITS 16]
real_mode:
;------ clear the PE bit ------
mov eax, cr0
xor eax, 1
mov cr0, eax
;------ do a far jump ------
jmp dword real2
real2:
hlt ; halts the CPU later it will really shutdown
jmp real2
Re:can't re-enter realmode
Posted: Tue Apr 06, 2004 8:24 am
by pini
You must clear the PM bit (bit 0 of cr0) to go back from protected mode.
Maybe you should use a "and" bitmask rather than a "xor", to ensure the bits are correctly cleared
Re:can't re-enter realmode
Posted: Tue Apr 06, 2004 8:28 am
by ich_will
you mean the PE (protection enable) bit of cr0, see Intel Manuel 4.1.3, i do it
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 2:01 am
by Candy
ich_will wrote:
you mean the PE (protection enable) bit of cr0, see Intel Manuel 4.1.3, i do it
clear it before the jump not after, and probably apply a segment prefix (realmode segment) and a 16-bit offset, not a 32-bit offset.
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 2:38 am
by ich_will
I clear it now before the jump and it seems to work.
I know its a stupid question but do you mean with:
and probably apply a segment prefix (realmode segment) and a 16-bit offset, not a 32-bit offset.
the jump introduction have to look like this:
jmp seg:offset ???????
But what should I write in seg and what in offset. I think I have to have an 16 Bit entry in the GDT or.
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 4:25 am
by tom1000000
Hello,
I hate to say this but it seems you are doing it all wrong.
I have written code that returns to real mode. IIRC this is what I did:
1) Setup a 16 bit protected mode code descriptor in your GDT, and ensure the page is identity mapped. You may also need a 16 bit data descriptor, I can't remember
2) Jump to 16 bit protected mode using a far jump
3) Turn off paging (reload CR3 to flush pages then clear PG bit)
4) Turn off protected mode (clear PE bit)
5) Far jump to 16 bit real mode code
6) Set DS etc
Also it is described in the Intel manuals how to return to real mode. Go read them.
Tom
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 4:56 am
by ich_will
i read it but it doesn't work, see the code at the top of that thread, it makes the things in steps like the intel manuel describes, without setting up stack etc.
1. How can I setup a GDT entry while I'm in pmode? For example if the bootloader which load my kernel don't do this.
2. I think I do a far jump (jmp 'dword' ...) or ??? If I write jmp far ... nasm outs: "error: a.out format does not support segment base references"
3. The intel manuel says: clear PG bit of cr0 than clear cr3
4. I do
5. see 2.
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 6:04 am
by Pype.Clicker
you're not doing a far jump: just a long jump ...
You should try harder to have the far jump encoded by NASM, (should be jmp far SELECTOR:dword offset)
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 6:09 am
by ich_will
Ok, but how can I setup a GDT entry while I'm in pmode? Or what should I do (f.e. if I don't know the GDT set up by the bootloader)?
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 6:40 am
by Pype.Clicker
the GDT setup process is exactly the same when you're in rmode or pmode: fill your GDT, write its *linear* address and size in a chunk of memory that you'll load with LDGT [...]
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 6:49 am
by Candy
short comment on the short-sightedness of some people in this thread, you don't need a new GDT entry. The point of making a new 16-bit segment, jumping to that, and then continuing with going to realmode in that segment is that you don't have to worry about prefixing properly. The point is, you should *always* prefix properly. Just like you can jump from 16-bit realmode to 32-bit protected mode (which even Intel and AMD don't seem to understand), you can jump from 32-bit protected mode back to 16-bit realmode. Just make sure you do a 66 EA <offset> <segment> and nothing else. Note also both the offset and segment are 16-bit.
If you like that more, you can always opt for the 16-bit code. If you want to be /REALLY/ sure you don't mess up, try taking the 512th GDT entry for the 16-bit code and identity-map it to 0x10000. This way, even the segments remain the same (of course, the hidden parts don't, so you need a reload anyway).
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 11:11 am
by ich_will
1. What do you mean with "66 EA <offset> <segment>"?
2. If I understood all right, I only have to jump to an 16 Bit
codesegment like:
Code: Select all
.
.
.
jmp real_mode
[Bits 16]
real_mode
How can I set the cs register to 16 Bit? If I only jump the cs register is still 32 bit. And it have to be 16 if I want use interrupts. And what else should I do?
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 11:21 am
by DennisCGc
1. What do you mean with "66 EA <offset> <segment>"?
Jmp dword segment:offset
when in real mode
And when in pmode:
Jmp word segment:offset
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 11:27 am
by Candy
ich_will wrote:
1. What do you mean with "66 EA <offset> <segment>"?
That the jump, after being assembled, should look like 0110011011101010xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy as a bit pattern, or 66EAxxxxyyyy as nibble pattern. xxxx == offset, yyyy == segment. At the moment it probably assembles to 11101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (E9xxxxxxxx)which makes for an in-segment jump. One that doesn't change the bit size for instance.
2. If I understood all right, I only have to jump to an 16 Bit
codesegment like:
Code: Select all
.
.
.
jmp real_mode
[Bits 16]
real_mode
How can I set the cs register to 16 Bit? If I only jump the cs register is still 32 bit. And it have to be 16 if I want use interrupts. And what else should I do?
The CS register is 16-bits all the time. The descriptor loaded in the CS register is always 64-bits. The segment pointed to by the descriptor loaded in the CS register can be 32 or 16 bits (or 64-bits on amd64). By reloading the CS register, and you do that by jumping with a far jump (encoded as EA), which in the case of a jump to a 16-bit segment should be prefixed with 66, and in the case of a jump to a 32-bit segment should be prefixed with 66, and must be prefixed with 66 if you want to jump beyond 0xFFFF.
Re:can't re-enter realmode
Posted: Wed Apr 07, 2004 11:59 am
by ich_will
i think this is nearly correct:
Code: Select all
__shutdown:
cli ; disable interrupts
;------ clear the PG bit ------
mov eax, cr0
xor eax, 0x80000000
mov cr0, eax
;------ clear the paging cache ------
xor eax, eax
mov cr3, eax
;------ clear the PE bit ------
mov eax, cr0
xor eax, 1
mov cr0, eax
;------ do a far jump to a 16-bit code segment ------
jmp word real_mode ;<---- something incorrect
[BITS 16]
real_mode:
hlt
please send me the correct line! :'( :-\
and please don't write
jmp word segment:offset
or
jmp word segment:real_mode
no! please help me. I make a pause, by me at home its 20:00pm. I read all the posts tomorrow and hop that i can correct it.
???
:-\ :'(