Page 1 of 2
switching into Real Mode
Posted: Tue Apr 27, 2004 11:30 am
by Wacky
Hi
I've written a function to switch from PMode into Real Mode.
But if i execute this funktion, the cpu triple faults!
This is the funktion:
Code: Select all
[global _shutdown]
_shutdown:
[BITS 32]
cli ; Interrupts werden verboten
mov eax, REAL_CODE_SEL
mov ss, eax
;nun wechseln wir in den 16-Bit Protected Mode
jmp dword REAL_CODE_SEL:prm
[BITS 16]
prm:
; Wir verlassen den Protected Mode
mov eax, cr0
and al, 0xFE
mov cr0, eax
jmp dword 0x00:rm
rm:
; Stack anpassen
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, 0x1000
mov ss, ax
; Die alte 16-Bit IDT wiederherstellen..
mov dx, 0x70
in al, dx
and al, 0x7F
out dx, al
sti
jmp $
; Shutdown will comming soon
The REAL_MODE_SEL:
Code: Select all
REAL_CODE_SEL equ $-gdt
dw 0xFFFF
dw 0
db 0
db 0x9A
db 0 ;16-bit
db 0
and this say Bochs:
Code: Select all
00968283000i[CPU ] protected mode
00968283000i[CPU ] CS.d_b = 32 bit
00968283000i[CPU ] SS.d_b = 32 bit
00968283000i[CPU ] | EAX=000006c4 EBX=00000fff ECX=00000064 EDX=0000000f
00968283000i[CPU ] | ESP=000006e0 EBP=000006e8 ESI=00000fff EDI=000c3000
00968283000i[CPU ] | IOPL=0 NV UP DI PL NZ NA PO NC
00968283000i[CPU ] | SEG selector base limit G D
00968283000i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00968283000i[CPU ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | CS:0018( 0003| 0| 0) 00000000 000fffff 1 1
00968283000i[CPU ] | EIP=ff80ae37 (ff80ae37)
00968283000i[CPU ] | CR0=0xe0000011 CR1=0x00000000 CR2=0x00000000
00968283000i[CPU ] | CR3=0x0009e000 CR4=0x00000000
00968283000i[ ] restoring default signal behavior
00968283000i[CTRL ] quit_sim called with exit code 1
Why does my code not work?
thx for every help.. wacky
Re:switching into Real Mode
Posted: Tue Apr 27, 2004 12:36 pm
by Pype.Clicker
considering the value of EIP, it looks that you're trying to return to realmode while being in the "high end" of the memory. Make sure your 'returning code" (both 16 and 32 bits) is 1:1 mapped below 1MB barrier will certainly lead to better results.
Re:switching into Real Mode
Posted: Tue Apr 27, 2004 12:38 pm
by ASHLEY4
This code works, look at the difference
.
Code: Select all
; switch to 16-bit protected mode on your way to real mode
jmp REAL_CODE_SEL:do_16
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 16-bit protected mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 16]
; switch to 16-bit stack and data
do_16: mov ax,REAL_DATA_SEL
mov ds,ax
mov ss,ax
nop
; push real-mode CS:IP
lea bx,[do_rm]
push bp
push bx
; clear PE [protected mode enable] bit and return to real mode
mov eax,cr0
and al,0xFE
mov cr0,eax
retf ; jumps to do_rm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 16-bit real mode again
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; restore real-mode segment register values
do_rm: mov ax,cs
mov ds,ax
mov ss,ax
nop
mov es,ax
mov fs,ax
mov gs,ax
; point to real-mode IDTR
lidt [ridtr]
; re-enable interrupts
sti
; exit to DOS with errorlevel 0
mov ax,0x4C00
int 0x21
ASHLEY4.
Re:switching into Real Mode
Posted: Tue Apr 27, 2004 2:23 pm
by Pype.Clicker
ouch ouch ouch ... loading SS with a CODE selector ??
honestly, if you really need to go back to real mode, i suggest you use a dos extender (pmode32, tran's Start32 or something alike) as base and study how and why it works ...
Re:switching into Real Mode
Posted: Fri Apr 30, 2004 9:25 am
by Wacky
ouch ouch ouch ... loading SS with a CODE selector ??
... ups! ::)
OK, now i've changed the code. The CPU is in Real-Mode
!
But i think there's still a Problem in my Far-Jump.
Please have a look at my (new) code:
Code: Select all
[global _shutdown]
_shutdown:
[BITS 32]
cli ; disable interrupts
; let's create a new stack
mov ax, REAL_DATA_SEL
mov ds, ax
mov ss, ax
; We're leaving PMode
mov eax, cr0
and al,0xFE
mov cr0, eax
jmp REAL_CODE_SEL:rm
[BITS 16]
rm:
; Stack-Stuff
mov ax, cs
mov dx, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
; restore the Real-Mode IDT
mov dx, 0x70
in al, dx
and al, 0x7F
out dx, al
sti
[...]
IMHO it should work! But BOCHS isn't my opinion.. :-\
Code: Select all
00071628830p[CPU ] >>PANIC<< prefetch: RIP > CS.limit
00071628830i[SYS ] Last time is 1083337951
00071628830i[CPU ] real mode
00071628830i[CPU ] CS.d_b = 16 bit
00071628830i[CPU ] SS.d_b = 16 bit
00071628830i[CPU ] | EAX=e0000010 EBX=00000fff ECX=00000064 EDX=0000001c
00071628830i[CPU ] | ESP=0000ffff EBP=0000075c ESI=00000fff EDI=000c3000
00071628830i[CPU ] | IOPL=0 NV UP DI PL NZ NA PO NC
00071628830i[CPU ] | SEG selector base limit G D
00071628830i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00071628830i[CPU ] | DS:0028( 0005| 0| 0) 00000000 0000ffff 0 0
00071628830i[CPU ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071628830i[CPU ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071628830i[CPU ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071628830i[CPU ] | SS:0028( 0005| 0| 0) 00000000 0000ffff 0 0
00071628830i[CPU ] | CS:0020( 0003| 0| 0) 00000200 0000ffff 0 0
00071628830i[CPU ] | EIP=ff800093 (ff800093)
00071628830i[CPU ] | CR0=0xe0000010 CR1=0x00000000 CR2=0x00000000
00071628830i[CPU ] | CR3=0x0009e000 CR4=0x00000000
00071628830i[ ] restoring default signal behavior
00071628830i[CTRL ] quit_sim called with exit code 1
>>PANIC<< prefetch: RIP > CS.limit
What does this mean? (Rest in peace, or what!
)
The Question is: Why does this happen and how can i fix this?
Thanks for all answers and tips... wacky
Re:switching into Real Mode
Posted: Fri Apr 30, 2004 9:41 am
by BI lazy
your eip is is outta 16 bit mode realms, so no wonder it crashes.
you oughta jump to a location *inside* the first 1 mb of memory IRC
Re:switching into Real Mode
Posted: Fri Apr 30, 2004 9:43 am
by DennisCGc
I think it's because you run this >1 MB, or anyway, you try to run this over the CS limit.
So I would suggest that you run this < 1MB.
HTH, DennisCGc.
Re:switching into Real Mode
Posted: Fri Apr 30, 2004 9:58 am
by Wacky
your eip is is outta 16 bit mode
Code: Select all
[...]
jmp REAL_CODE_SEL:rm
[BITS 16]
rm:
[...]
Shouldn't this be enought to set the eip < 1MB ? ???
If not, what is the best way to do this?
Re:switching into Real Mode
Posted: Fri Apr 30, 2004 10:14 am
by BI lazy
the problem is that you issue this jmp with 32 bit code albeit it is expected to be 16 bit code.
look at ashleys code. It should show you exactly, where the heck the dog is buried. (*chuckle* I'd prefer some juicy english idiom instead of a lame translation of a german one)
Re:switching into Real Mode
Posted: Sun May 02, 2004 7:16 am
by ich_will
My shutdown.asm: all works fine, I copy this function to 0x500
and jmp to it. But if i try to jump into realmode like this:
jmp word 0x20:real_mode (0x20 is the same selector Wacky sends as real_mode_sel)
bochs ends with:
00020520492i[CPU ] real mode
00020520492i[CPU ] CS.d_b = 16 bit
00020520492i[CPU ] SS.d_b = 16 bit
00020520492i[CPU ] | EAX=6000004d EBX=00000400 ECX=00000005 EDX=000003d8
00020520492i[CPU ] | ESP=00007fdc EBP=0000f829 ESI=0000f8fe EDI=000079d0
00020520492i[CPU ] | IOPL=0 NV UP DI PL NZ NA PE CY
00020520492i[CPU ] | SEG selector base limit G D
00020520492i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00020520492i[CPU ] | DS:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00020520492i[CPU ] | ES:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00020520492i[CPU ] | FS:0018( 0003| 0| 0) 00000000 0000ffff 0 0
00020520492i[CPU ] | GS:0018( 0003| 0| 0) 00000000 0000ffff 0 0
00020520492i[CPU ] | SS:9000( 0003| 0| 0) 00090000 0000ffff 0 0
00020520492i[CPU ] | CS:fcaf( 0005| 0| 0) 000fcaf0 0000ffff 0 0
00020520492i[CPU ] | EIP=00010510 (0001050f)
00020520492i[CPU ] | CR0=0x60000010 CR1=0x00000000 CR2=0x00000000
00020520492i[CPU ] | CR3=0x00000000 CR4=0x00000000
00020520492i[ ] restoring default signal behavior
========================================================================
Bochs is exiting with the following message:
[CPU ] prefetch: RIP > CS.limit
========================================================================
00020520492i[CTRL ] quit_sim called with exit code 1
EIP haven't every time the same value, but most 00007a0f. Or if I call an interrupt bochs ends with:
00026795750i[CPU ] real mode
00026795750i[CPU ] CS.d_b = 16 bit
00026795750i[CPU ] SS.d_b = 16 bit
00026795750i[CPU ] | EAX=600000f9 EBX=00000001 ECX=00000001 EDX=00000007
00026795750i[CPU ] | ESP=00000001 EBP=00007fca ESI=00000004 EDI=00000000
00026795750i[CPU ] | IOPL=0 NV UP DI NG NZ NA PE NC
00026795750i[CPU ] | SEG selector base limit G D
00026795750i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00026795750i[CPU ] | DS:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00026795750i[CPU ] | ES:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00026795750i[CPU ] | FS:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00026795750i[CPU ] | GS:0000( 0003| 0| 0) 00000000 0000ffff 0 0
00026795750i[CPU ] | SS:9000( 0003| 0| 0) 00090000 0000ffff 0 0
00026795750i[CPU ] | CS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00026795750i[CPU ] | EIP=00000000 (00000000)
00026795750i[CPU ] | CR0=0x60000010 CR1=0x00000000 CR2=0x00000000
00026795750i[CPU ] | CR3=0x00000000 CR4=0x00000000
00026795750i[ ] restoring default signal behavior
========================================================================
Bochs is exiting with the following message:
[CPU ] CPU shutting down due to lack of stack space, SP==1
========================================================================
00026795750i[CTRL ] quit_sim called with exit code 1
before I load a Pmode IDT i save the real_mode IDT with this:
Code: Select all
old_idt:
dw (256*8)-1
dd 0x6000
...
sidt [old_idt] ; save idt
Code: Select all
[ORG 0x500]
[BITS 32]
;------ clear the PG bit ------
mov eax, cr0
xor eax, 0x80000000
mov cr0, eax
;------ clear the paging cache ------
xor eax, eax
mov cr3, eax
mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;------ 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 0x00:real_mode
[BITS 16]
msg1 db "Test Text",0
real_mode:
lidt [real_idt_desc]
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, 0x9000
mov ss, ax
mov esp, 0x8000
mov si, msg1
call putstr
cli
hlt
real_idt_desc:
dw (256*8)-1
dd 0x6000
putstr:
lodsb ; load the next character
or al,al ; if al = 0 (= character)
jz short putstrd ; return
mov ah, 0x0E ; function 0x0E (display character)
mov bh, 0x00 ; current page
mov bl, 0x07 ; color
int 0x10 ; call display interrupt
jmp putstr
putstrd:
ret
Re:switching into Real Mode
Posted: Sun May 02, 2004 10:09 am
by ASHLEY4
Take a look at the code i posted ,it works fine.
ASHLEY4.
Re:switching into Real Mode
Posted: Mon May 03, 2004 1:38 am
by Pype.Clicker
Wacky, i think you cannot so simply get back to real mode in the 32bits framework you've set up ... I suggest you take the following actions:
- make sure you didn't touch the real mode IVT nor the BIOS Data Area
- Make sure your 16 bits code contains no reference except references relative to the 16bits code itself (it should be assemblable as a separate .asm to a .com, for instance). Put an 'ORG 0' at the start of that 16 bits section.
- allocate some 16 bytes-aligned memory area between 0:0x1000 and 0x9000:0xffff. Copy your 16bits code there.
- compute the segment value of that allocated memory
- have a 16 bits protected mode descriptor that points wherever you wish (Hint: make sure your p16: is either in the first 64K or that the code16 descriptor has a base that will allow p16 to stay in the 64K limit.
- jump to code within that protected descriptor (jmp CODE16:p16_relative_to_code16_base)
- disable interrupts, reload all data selectors (including stack) with a DATA16, 64K-limited selector. Reload IDTR with IVT values
- clear the PM and PG bits of CR0 at once
- jump to your realmode terminator code (jmp <computed_segment>:0 )
- reload data segments with valid realmode values.
- enable interrupts and terminate your program.
All 'BITS 16' does is telling your assembler the following bytes should be assembled for 16 bits decoding. Nothing more ... Nothing less ...
Re:switching into Real Mode
Posted: Mon May 03, 2004 8:55 am
by Therx
couldn't you go into unreal mode so you can still access the full address space but also have BIOS access?
Pete
Re:switching into Real Mode
Posted: Mon May 03, 2004 9:06 am
by Pype.Clicker
Pete wrote:
couldn't you go into unreal mode so you can still access the full address space but also have BIOS access?
Pete
That won't solve his problem, imho. Even in unreal mode,
code needs to be below 1MB and within a 64KB segment ... any attempt to enfringe this rule will break things badly
Re:switching into Real Mode
Posted: Mon May 03, 2004 10:38 am
by ASHLEY4
I would do this:
In real mode before going to pmode (eg: under 1mb)
Code: Select all
mov ax,cs
mov [real_mode_cs],ax
lea ax,[we_are_inreal_mode]
mov [Real_mode_IP],ax
jmp OverThisCode
[bits 16]
we_are_inreal_mode:
;Put you real mode code here,that you want to jump back to.
;you must put realmode compaible reg in seg regs.
;you most restore the realmode ivt and then you can re-enable int's
OverThisCode:
Next we can do this,and you must diss-able int's first.
Code: Select all
jmp REAL_MODE_SEL:we_are_in_16bit_pmode
[bits 16]
we_are_in_16bit_pmode:
mov ax,REAL_DATA_SEL
mov ss,ax
mov ds,ax
mov eax,cr0
and al,0xfe
mov cr0,eax
jmp far [Real_mode_IP]
Code: Select all
Real_mode_IP:
dw 0
real_mode_cs:
dw 0
This code has not been tested.
PS: Does any one know if you need to remap the pic's,when going from pmode to realmode and back to pmode ?,
I know you do when first going to pmode.
ASHLEY4.