blob: 06141955fd18e62dc0e16923a23d29c1ad58bc63 [file] [log] [blame]
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* Mostly stolen from the GRUB2 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
*
*/
/**
* @file
* @brief Switch from the flat mode world into the real mode world and vice versa
*
* Note: These functions are *called* and return in a different operating mode
*/
/**
* @fn void real_to_prot(void)
* @brief Switch from temp. real mode back to flat mode
*
* Called from a 32 bit flat mode segment and returns into a 16 bit segment
*/
/**
* @fn void prot_to_real(void)
* @brief Switch from flat mode to real mode
*
* Called from a 16 bit real mode segment and returns into a 32 bit segment
*/
#include <asm/modes.h>
.file "walkyrie.S"
/* keep the current flat mode stack pointer, while playing in real mode */
.section .boot.data.protstack
.code32
protstack: .long 4
/* temp. store */
return_addr: .long 4
.section .boot.text.real_to_prot, "ax"
.code16
.globl real_to_prot
.type real_to_prot, @function
/* Note: This routine should not change any other standard registers than eax */
real_to_prot:
/*
* Always disable the interrupts, when returning to flat mode
*/
cli
/* turn on protected mode */
movl %cr0, %eax
orl $0x00000001, %eax
movl %eax, %cr0
/* jump to relocation, flush prefetch queue, and reload %cs */
DATA32 ljmp $__BOOT_CS, $return_to_flatmode
/* ----------------------------------------------------------------------- */
.section .boot.text.return_to_flatmode, "ax"
.type return_to_flatmode, @function
.code32
return_to_flatmode:
/* reload other segment registers */
movw $__BOOT_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* move the return address from the real mode to the flat mode stack */
movl (%esp), %eax
movl %eax, return_addr
/* setup again the flat mode stack */
movl protstack, %eax
movl %eax, %esp
movl %eax, %ebp
movl return_addr, %eax
movl %eax, (%esp)
/* flag we returned happy here */
xorl %eax, %eax
ret
.size real_to_prot, .-real_to_prot
/* ------------------------------------------------------------------------ */
/* Note: This routine should not change any other standard registers than eax */
.section .boot.text.prot_to_real, "ax"
.globl prot_to_real
.type prot_to_real, @function
.extern boot_stack
.code32
prot_to_real:
/* save the protected mode stack */
movl %esp, %eax
movl %eax, protstack
/* prepare the real mode stack */
/* - address to call to the top of this stack */
movl (%esp), %eax
movl %eax, boot_stack - 4
/* - the stack itself */
movl $boot_stack - 4, %eax
movl %eax, %esp
movl %eax, %ebp
/* prepare segments limits to 16 bit */
movw $__REAL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* at last, also limit the code segment to 16 bit */
ljmp $__REAL_CS, $return_to_realmode
/* ----------------------------------------------------------------------- */
.section .boot.text.return_to_realmode, "ax"
return_to_realmode:
.code16
/* disable protected mode */
movl %cr0, %eax
andl $(~0x00000001), %eax
movl %eax, %cr0
/*
* all the protected mode settings are still cached in the CPU.
* Refresh them by re-loading all registers in realmode
* Start with the CS, continue with the data registers
*/
ljmp $0, $enter_realmode
enter_realmode:
xorl %eax, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/*
* back in plain real mode now, we can play again with the BIOS
*/
/* restore interrupts */
sti
/* return on realmode stack! */
DATA32 ret
.size prot_to_real, .-prot_to_real