/* * (C) Copyright 2002 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ /* 32bit -> 16bit -> 32bit mode switch code */ /* * Stack frame at 0xe00 * e00 ebx; * e04 ecx; * e08 edx; * e0c esi; * e10 edi; * e14 ebp; * e18 eax; * e1c ds; * e20 es; * e24 fs; * e28 gs; * e2c orig_eax; * e30 eip; * e34 cs; * e38 eflags; * e3c esp; * e40 ss; */ #define a32 .byte 0x67; /* address size prefix 32 */ #define o32 .byte 0x66; /* operand size prefix 32 */ .section .realmode, "ax" .code16 /* 16bit protected mode code here */ .globl realmode_enter realmode_enter: o32 pusha o32 pushf cli sidt saved_idt sgdt saved_gdt movl %esp, %eax movl %eax, saved_protected_mode_esp movl $0x10, %eax movl %eax, %esp movw $0x28, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs lidt realmode_idt_ptr movl %cr0, %eax /* Go back into real mode by */ andl $0x7ffffffe, %eax /* clearing PE to 0 */ movl %eax, %cr0 ljmp $0x0,$do_realmode /* switch to real mode */ do_realmode: /* realmode code from here */ movw %cs,%ax movw %ax,%ds movw %ax,%es movw %ax,%fs movw %ax,%gs /* create a temporary stack */ movw $0xc0, %ax movw %ax, %ss movw $0x200, %ax movw %ax, %sp popl %ebx popl %ecx popl %edx popl %esi popl %edi popl %ebp popl %eax movl %eax, temp_eax popl %eax movw %ax, %ds popl %eax movw %ax, %es popl %eax movw %ax, %fs popl %eax movw %ax, %gs popl %eax /* orig_eax */ popl %eax cs movw %ax, temp_ip popl %eax cs movw %ax, temp_cs o32 popf popl %eax popw %ss movl %eax, %esp cs movl temp_eax, %eax wbinvd /* self-modifying code, * better flush the cache */ .byte 0x9a /* lcall */ temp_ip: .word 0 /* new ip */ temp_cs: .word 0 /* new cs */ realmode_ret: /* save eax, esp and ss */ cs movl %eax, saved_eax movl %esp, %eax cs movl %eax, saved_esp movw %ss, %ax cs movw %ax, saved_ss /* restore the stack, note that we set sp to 0x244; * pt_regs is 0x44 bytes long and we push the structure * backwards on to the stack, bottom first */ movw $0xc0, %ax movw %ax, %ss movw $0x244, %ax movw %ax, %sp xorl %eax,%eax cs movw saved_ss, %ax pushl %eax cs movl saved_esp, %eax pushl %eax o32 pushf xorl %eax,%eax cs movw temp_cs, %ax pushl %eax cs movw temp_ip, %ax pushl %eax pushl $0 movw %gs, %ax pushl %eax movw %fs, %ax pushl %eax movw %es, %ax pushl %eax movw %ds, %ax pushl %eax movl saved_eax, %eax pushl %eax pushl %ebp pushl %edi pushl %esi pushl %edx pushl %ecx pushl %ebx o32 cs lidt saved_idt o32 cs lgdt saved_gdt /* Set GDTR */ movl %cr0, %eax /* Go back into protected mode */ orl $1,%eax /* reset PE to 1 */ movl %eax, %cr0 jmp next_line /* flush prefetch queue */ next_line: movw $return_ptr, %ax movw %ax,%bp o32 cs ljmp *(%bp) .code32 protected_mode: movl $0x18,%eax /* reload GDT[3] */ movw %ax,%fs /* reset FS */ movw %ax,%ds /* reset DS */ movw %ax,%gs /* reset GS */ movw %ax,%es /* reset ES */ movw %ax,%ss /* reset SS */ movl saved_protected_mode_esp, %eax movl %eax, %esp popf popa ret temp_eax: .long 0 saved_ss: .word 0 saved_esp: .long 0 saved_eax: .long 0 realmode_idt_ptr: .word 0x400 .word 0x0, 0x0 saved_gdt: .word 0, 0, 0, 0 saved_idt: .word 0, 0, 0, 0 saved_protected_mode_esp: .long 0 return_ptr: .long protected_mode .word 0x10