Go to Real Mode and return to Protected Mode

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
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Go to Real Mode and return to Protected Mode

Post by Jeko »

I used this code for exec a real mode code:

Code: Select all

static unsigned long long real_mode_gdt_entries [3] =
{
	0x0000000000000000ULL,	// Null descriptor.
	0x00009a000000ffffULL,	// 16-bit real-mode 64k code at 0x00000000
	0x000092000100ffffULL	// 16-bit real-mode 64k data at 0x00000100
};

static struct
{
	unsigned short       size __attribute__ ((packed));
	unsigned long long * base __attribute__ ((packed));
}
	//! Real mode GDT register.
	real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
	//! Real mode IDT register.
	real_mode_idt = { 0x3ff, 0 };

//! \brief Switch back to real mode.
//! \note This is embedded code.
static unsigned char real_mode_switch[] =
{
	0x66, 0x0f, 0x20, 0xc0,				// movl %cr0, %eax
	0x66, 0x83, 0xe0, 0x11,				// andl $0x00000011, %eax
	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,		// orl $0x60000000, %eax
	0x66, 0x0f, 0x22, 0xc0,				// movl %eax, %cr0
	0x66, 0x0f, 0x22, 0xd8,				// movl %eax, %cr3
	0x66, 0x0f, 0x20, 0xc3,				// movl %cr0, %ebx
	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	// andl $0x60000000, %ebx
	0x74, 0x02,					// jz 1f
	0x0f, 0x09,					// wbinvd
	0x24, 0x10,					// 1: andb $0x10, %al
	0x66, 0x0f, 0x22, 0xc0,				// movl %eax, %cr0
	// Reflush %cs register.
	0xea, 0x00, 0x10, 0x00, 0x00,			// ljmp $0x00, $0x1000
};


void machine_real_exec( unsigned char *code, int length )
{
	size_t addr;

	asm("cli");

	// Identical map first 64k of memory.
	for( addr=0; addr<0x10000; addr+=PAGE_SIZE )
	{
		if( !map_page( addr, addr, READ_WRITE | PRESENT ) )
		{
			// Something wrong with page-mapping =>
			// force a triple fault...
			__asm__ __volatile__ ( "lidt (%0)" : : "r"(no_idt) );
			__asm__ __volatile__ ( "int3" );
		}
	}
	flush_tlb_all();

	// Copy the real-mode switch code below the first page.
	memcpy( (void *)(0x1000-sizeof(real_mode_switch)),
		real_mode_switch, sizeof(real_mode_switch)
	);
	// Copy the real-mode code to the first page.
	memcpy( (void *)(0x1000), code, length );

	// Setup IDT for real mode.
	__asm__ __volatile__ ( "lidt %0" : : "m"(real_mode_idt) );

	// Setup GDT for real mode.
	__asm__ __volatile__ ( "lgdt %0" : : "m"(real_mode_gdt) );

	// Load data segment registers.
	__asm__ __volatile__ (
		"movl $0x10, %%eax\n"
		"movl %%eax, %%ds\n"
		"movl %%eax, %%es\n"
		"movl %%eax, %%fs\n"
		"movl %%eax, %%gs\n"
		"movl %%eax, %%ss"
		: : : "eax"
	);
	// Jump to the 16-bit code.
	__asm__ __volatile__ (
		"ljmp $0x0008, %0"
		: : "i"((void *)(0x1000-sizeof(real_mode_switch)))
	);
}
For example to reboot the PC I used this code:

Code: Select all

static unsigned char jump_to_bios_reboot[] =
{
	0xea, 0x00, 0x00, 0xff, 0xff,		// ljmp $0xffff, $0x0000
};

void reboot()
{
	asm("cli");

	machine_real_exec( jump_to_bios_reboot, sizeof(jump_to_bios_reboot) );
}
If I want return to protected mode, how can I do? (Naturally if I, for example, use a code for change the video mode)

I took this code from an opensource project, but I don't remember what.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Take a look at my DemoVesa example, it includes code that goes to and from Pmode for mode switching http://www.dex4u.com/tuts/DemoVesa.zip
Simple example:
If you set your GDT descriptor up right, it as simple as call a function like this:

Code: Select all

;:::::::::::::::::::::::::::::::::::::::::::::::::::::;
; Back to realmode for vesa int's.                
;::::::::::::::::::::::::::::::::::::::::::::::::::::;

Real_Mode_vesa_int:
        pushad

        jmp   20h:do_16v
use16

do_16v:

        mov   ax,28H
	mov   ds,ax
	mov   ss,ax
	nop


	mov   bx,[RealModeCS]                   ; push real-mode CS:IP
	push  bx
	lea   bx,[do_rm]
	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  ;
;.........................;

do_rm:	
        mov   ax,cs                             ; restore real-mode segment register values
	mov   ds,ax
	mov   ss,ax
	nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax

	lidt  [ridtr]                          ; point to real-mode IDTR

        push  cs
	pop   ds
        push  ds
        pop   es
        mov   ax,0xB800
	mov   es,ax


;''''''''''''''''''''''''''';
;  16-bit real mode int's   ;
;...........................;

        ;------------------------------------------------------------
        ; Purpose: Sets the graphics mode.
        ; Outputs: (1 on error, 0 otherwise) We do no error checking,i will leave that to you.
        ;
        ; Notes:   Assumes function "4f00h" & "4f01h" has been called to determine if VESA is
        ;          available and to fill the various structures necessary for
        ;          this function to work.
        ;------------------------------------------------------------
        sti                                    ; re-enable interrupts
        mov   ax,4f02h                         ; set vesa screen mode
        mov   bx,0x4112                        ; 4112h = 32/24bit
        int   10h
        cli                                    ; Disable interrupts,
;''''''''''''''''''''''''''';
;  real mode int's end      ;
;...........................;

        lgdt  [gdtr]                           ; Load the GDTR with the base address and limit of the GDT

	mov   eax,cr0                          ; Set the PE [protected mode enable] bit in register CR0
	or    al,1
	mov   cr0,eax


	jmp   sys_code:do_pm11                 ; jumps to do_pm


;''''''''''''''''''''''''''';
;  32-bit protected  mode   ;
;...........................;
use32
do_pm11:

      	mov   ax,sys_data
        mov   ds,ax
        mov   ss,ax
        nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax

        mov   ax,8h
	mov   es,ax

        popad

        ret
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Back to realmode for textmode int's.                                 
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
To change vesa mode (or any bios int), NOTE: The vesa info and availableaty has already been checked for on boot up.
Post Reply