blob: d6c74ecd79b4cea61a5e5b391441b6a11cf512f2 [file] [log] [blame]
/*
* (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