diff options
Diffstat (limited to 'arch/i386/lib/realmode_switch.S')
| -rw-r--r-- | arch/i386/lib/realmode_switch.S | 222 | 
1 files changed, 222 insertions, 0 deletions
| diff --git a/arch/i386/lib/realmode_switch.S b/arch/i386/lib/realmode_switch.S new file mode 100644 index 000000000..d6c74ecd7 --- /dev/null +++ b/arch/i386/lib/realmode_switch.S @@ -0,0 +1,222 @@ +/* + * (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 |