|  | /* | 
|  | * (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 |