| /* |
| * (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 |
| /* Go back into real mode by clearing PE to 0 */ |
| movl %cr0, %eax |
| andl $0x7ffffffe, %eax |
| movl %eax, %cr0 |
| |
| /* switch to real mode */ |
| ljmp $0x0,$do_realmode |
| |
| 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 |
| |
| /* self-modifying code, better flush the cache */ |
| wbinvd |
| |
| .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 |
| |
| /* Go back into protected mode reset PE to 1 */ |
| movl %cr0, %eax |
| orl $1,%eax |
| movl %eax, %cr0 |
| |
| /* flush prefetch queue */ |
| jmp next_line |
| next_line: |
| movw $return_ptr, %ax |
| movw %ax,%bp |
| o32 cs ljmp *(%bp) |
| |
| .code32 |
| protected_mode: |
| /* Reload segment registers */ |
| movl $0x18, %eax |
| movw %ax, %fs |
| movw %ax, %ds |
| movw %ax, %gs |
| movw %ax, %es |
| movw %ax, %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 |