Skip to content
Snippets Groups Projects
realmode_switch.S 4.08 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * (C) Copyright 2002
     * Daniel Engstrm, Omicron Ceti AB, daniel@omicron.se
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *
    
     * 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
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *	e00 ebx;
    
     *	e04 ecx;
     *	e08 edx;
     *	e0c esi;
     *	e10 edi;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *	e14 ebp;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *	e1c ds;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *	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 */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #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
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	sidt	saved_idt
    	sgdt	saved_gdt
    	movl	%esp, %eax
    	movl	%eax, saved_protected_mode_esp
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	movl	$0x10, %eax
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	movl	%eax, %esp
    
    	movw	$0x28, %ax
    	movw	%ax, %ds
    	movw	%ax, %es
    	movw	%ax, %fs
    	movw	%ax, %gs
    
    	lidt	realmode_idt_ptr
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	movl	%cr0, %eax			/* Go back into real mode by */
    	andl	$0x7ffffffe, %eax		/* clearing PE to 0 */
    
    	movl	%eax, %cr0
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	ljmp	$0x0,$do_realmode		/* switch to real mode */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    do_realmode:					/* realmode code from here */
    
    	movw	%cs,%ax
    	movw	%ax,%ds
    	movw	%ax,%es
    	movw	%ax,%fs
    	movw	%ax,%gs
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    						/* create a temporary stack */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	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
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	wbinvd					/* self-modifying code,
    
    						 * better flush the cache */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	.byte	0x9a				/* lcall */
    temp_ip:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0				/* new ip */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    temp_cs:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0				/* new cs */
    
    realmode_ret:
    						/* save eax, esp and ss */
    cs	movl	%eax, saved_eax
    	movl	%esp, %eax
    cs	movl	%eax, saved_esp
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	movw	%ss, %ax
    
    cs	movw	%ax, saved_ss
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/* 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 */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	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
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    o32 cs	lgdt	saved_gdt			/* Set GDTR */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	movl	%cr0, %eax			/* Go back into protected mode */
    	orl	$1,%eax	/* reset PE to 1 */
    	movl	%eax, %cr0
    	jmp	next_line			/* flush prefetch queue */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    next_line:
    	movw	$return_ptr, %ax
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	movw	%ax,%bp
    
    o32 cs	ljmp	*(%bp)
    
    .code32
    protected_mode:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	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
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	ret
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0
    
    saved_esp:
    	.long	0
    saved_eax:
    	.long	0
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    realmode_idt_ptr:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0x400
    	.word	0x0, 0x0
    
    saved_gdt:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0, 0, 0, 0
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.word	0, 0, 0, 0
    
    
    saved_protected_mode_esp:
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	.long	0
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    return_ptr:
    	.long	protected_mode
    	.word	0x10