Page 1 of 1

Protected - Realmode Switching. [SOLVED]

Posted: Wed Apr 09, 2008 4:39 pm
by joegy
Hi,

I am trying to implement protected - real mode switching. The code below is supposed to run on a protected mode os and is eventually supposed to enable vesa activation through 10h interrupt and then switch back to beloved protected mode . The routine _exit_pmode is integrated into the c++ project files of my os-code through a c++-header file with the corresponding inline code. I have most of the code off this forum. Thanks so far!
I am working with linux and nasm 0.98.38. So the errors I am getting are 1st:
' relocation truncated to fit: R_386_16 against ' when trying to compile. It must have something to do with me not being in 16 bit code when I should be, I also read about that here and on the net. (Ah, and the org directive doesn't work)
2: I can compile with no errors when I add the option '-Ttext 0xEFFF' to ld in the Makefile which I understand is supposed to tell the linker that the code should be put to that adress. Well if I do this and run the system in bochs the bochs-cpu triple-faults. Could this have something to do with the code messing with my startup code?

I have been looking around in the web for quite a while now. I would really appreciate some specific response to my problem! Thanks so much!

Best,
joegy

Code: Select all

_exit_pmode:   ; method exported to c++ to exit protected mode

[BITS 32]
    jmp REAL_CODE_SEL:do_16
[BITS 16]
do_16:
    ; disable interrupts
    cli

    ; let's create a new stack / load SS with real mode values
    mov   ax, REAL_DATA_SEL
    mov   ds, ax
    mov   ss, ax
    nop 

    ; push real-mode CS:IP
    mov bx,[RealModeCS]
    push bx
    lea bx,[RealMode]
    push bx 
    ;lea bx,[RealMode]
    ;push bp
    ;push bx

    ; Exit Protected Mode
    mov   eax, cr0
    and  al,0xFE
    mov   cr0, eax
    sti
    ret
    ;jmp  REAL_CODE_SEL:RealMode


RealMode: 
    ; Stack-Stuff / Load all data segment registers with real mode values
    mov   ax, cs
    mov   ds, ax
    mov   ss, ax
    nop
    mov   es, ax
    mov   fs, ax
    mov   gs, ax
    
    ; restore the Real-Mode IDT
    lidt [ridtr]
    ;mov   dx, 0x70
    ;in   al, dx
    ;and   al, 0x7F
    ;out   dx, al 
    
    ;enable interrupts
    sti
    ret

[SECTION .data]

gdt0 equ $ ; null entry
GDT:
.Entry0: dw 0 ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0 ; type
db 0 ; limit 19:16, flags
db 0 ; base 31:24


REAL_CODE_SEL equ $-gdt0 ; code segment descriptor for 16 bit mode

.Entry1: dw 0xFFFF
dw 0x0 ; base
db 0x0 ; base
db 0x9A ; present, ring 0, code, non-conforming, readable
db 0x00 ; 16 bit
db 0

REAL_DATA_SEL equ $-gdt0 ; data segment descriptor for 16 bit mode

.Entry2: dw 0xFFFF
dw 0x0 ; base
db 0x0 ; base
db 0x92 ; present, ring 0, data, expand-up, writable
db 0x00 ; 16 bit
db 0


RealModeCS equ $-gdt0
.Entry3:
    dw 0

ridtr equ $-gdt0
.Entry4:
    dw 0xFFFF           ; limit=0xFFFF
    dd 0		; base=0

Posted: Wed Apr 09, 2008 5:09 pm
by Combuster
well the problem is that as soon as you enter 16-bit protected mode, you can access only 64k of code. When you continue and enter real mode you can only access the first 1MB of memory. So you will have to copy your code there, and rewrite the code to match that fixed address.

other notes:
you use a selector as a real mode segment
you haven't changed to a real-mode compatible stack.
use bochs' debugger

Posted: Thu Apr 10, 2008 2:05 am
by joegy
Combuster, thanks so much for the answer. How do I copy code? I thought that went with the org statement, but that doesn't work.
An answer or link on this would be appreciated!

Best,
joegy

Posted: Thu Apr 10, 2008 2:18 am
by Combuster
joegy wrote:How do I copy code?
memcpy()? rep movsb?

Code: Select all

mov esi, do_16bit_pm
mov edi, location_under_64k
mov eax, size_of_function
cld
rep movsb
jmp code_16:location_under_64k

do_16bit_pm:
; bla bla bla

Posted: Thu Apr 10, 2008 2:54 am
by East
joegy Can you please elaborate the process of switching from protected mode to real mode since i am also trying it in linux.

Posted: Thu Apr 10, 2008 4:43 am
by Combuster
East wrote:joegy Can you please elaborate the process of switching from protected mode to real mode since i am also trying it in linux.
Ghod, DON'T YOU EVER READ WHAT PEOPLE TELL YOU? YOU CAN NOT SWITCH MODES IN LINUX. This is the third thread in which you asked the same question, and this is therefore my last warning to you. The next offence will make me send a ban proposal to the other moderators.

I recommend you to leave these forums, as you do not meet the prerequisites as stated in the rules, and you apparently do not have the intellect to ever attain those.

@joegy: apologies for the thread hijack.

Posted: Thu Apr 10, 2008 10:13 am
by joegy
Compuster, excuse me that I am asking again, you may have noticed that I am new to this.
I suppose that with 'do_16bit_pm' you mean my inadequately named function 'do_16'. Right?
How do I calculate the size of a function? Is code_16 a variable? Can I just take any location under 64 K?
Sorry for the 'newbie' questions!

Best,
joegy

Posted: Thu Apr 10, 2008 4:32 pm
by Combuster
joegy wrote:Compuster, excuse me that I am asking again, you may have noticed that I am new to this.
I don't mind newcomers to OS development, but you might want to do some more practice in assembly.
I suppose that with 'do_16bit_pm' you mean my inadequately named function 'do_16'. Right?
that name comes from the fact that there are three modes you pass through when switching to real mode: 32-bit protected mode, 16-bit protected mode, and real mode. The jump you see is part of that first switch. Later you'll do another far jump to fully enter real mode.
How do I calculate the size of a function?
By checking where it ends:

Code: Select all

function_start:
    bla
    bla
    bla
function_end:

function_size equ function_end - function_start
the method btw works for more than just functions.
Is code_16 a variable?
constant, the selector representing the 16-bit code segment
Can I just take any location under 64 K?
You can take almost any location between begin of memory and 1M+64k. However, to do so, you get a non-zero segment offset. Which means that you have to change the GDT entry for the 16-bit code segment, and compute a segment value for real mode so that you don't drop out of the code sequence into some random piece of memory.

Posted: Fri Apr 11, 2008 9:58 am
by joegy
Thanks Combuster! I got an assembly book from the library today. Do you know of an operating system where somebody does a "protected mode - real mod switch" and then enables vesa and then goes back to protected mode? (with source available) A lot of the os'es I have been looking at use some kind of int86 spinoff. Do YOU think the here wanted mode switch is a good way to get vesa working?

I got a little unsure if it is a good idea to do a mode switch only because of interrupt. Well, looking forward to your answer!

Posted: Fri Apr 11, 2008 10:13 am
by einsteinjunior
I think the only whay here is to write a virtual 8086 Machine Monitor then do the interrupt calls from there.
You should be able then to switch to vesa mode without even leaving protected mode.

Posted: Fri Apr 11, 2008 5:10 pm
by binutils
joegy wrote:Do you know of an operating system where somebody does a "protected mode - real mod switch" and then enables vesa and then goes back to protected mode? (with source available)
freedos?

Posted: Fri Apr 11, 2008 7:56 pm
by bewing
einsteinjunior wrote:I think the only whay here is to write a virtual 8086 Machine Monitor then do the interrupt calls from there.
You should be able then to switch to vesa mode without even leaving protected mode.
No, joegy is correct -- you can do it either way. Dex uses a realmode switch. Brendan thinks that V86 is superior. If you use realmode, you lose all the incoming interrupts during the vesa mode switch, which could take several seconds. But if you use V86, it uses segments, and you have to multitask it, so your task switcher code needs to carefully preserve segment registers through task switches (ouch).

Posted: Sat Apr 12, 2008 7:26 pm
by Dex
bewing is right, i use a switch to realmode for vesa mode switching, here is a simple demo to show it working, but its up to you to find the method that suit you best.
http://www.dex4u.com/demos/VesaDemo.zip

Posted: Fri May 30, 2008 3:03 am
by joegy
Alright, switching into Realmode and back and enabling VBE-Mode - calling ints - works.

The VBE-Mode number is put into memory by the calling c++ function.
The Code is copied to a realmode compatible position in memory: 0x5000.

Thanks everyone, especially DEX and Combuster!!!!