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 :D !
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.