Go to Real Mode and return to Protected Mode
Posted: Thu Mar 01, 2007 9:04 am
I used this code for exec a real mode code:
For example to reboot the PC I used this code:
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.
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)))
);
}
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) );
}
I took this code from an opensource project, but I don't remember what.