aboutsummaryrefslogtreecommitdiff
path: root/src/arch/i386/boot/wakeup.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/i386/boot/wakeup.S')
-rw-r--r--src/arch/i386/boot/wakeup.S126
1 files changed, 70 insertions, 56 deletions
diff --git a/src/arch/i386/boot/wakeup.S b/src/arch/i386/boot/wakeup.S
index 7915fc38c5..b348e95a71 100644
--- a/src/arch/i386/boot/wakeup.S
+++ b/src/arch/i386/boot/wakeup.S
@@ -2,10 +2,11 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 2009 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2 as published by
- * the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,76 +17,89 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
- .text
- .code32
- .globl acpi_jmp_to_realm_wakeup
- /* This function does the PM -> RM switch, but
- it can run >1MB even in real mode */
-acpi_jmp_to_realm_wakeup:
- mov 0x4(%esp), %eax
+#define WAKEUP_BASE 0x600
+#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE)
+
+/* CR0 bits */
+#define PE (1 << 0)
+
+ .code32
+ .globl __wakeup
+__wakeup:
+ /* First prepare the jmp to the resume vector */
+ mov 0x4(%esp), %eax /* vector */
/* last 4 bits of linear addr are taken as offset */
andw $0x0f, %ax
- movw %ax, (jmp_off)
+ movw %ax, (__wakeup_offset)
mov 0x4(%esp), %eax
/* the rest is taken as segment */
shr $4, %eax
- movw %ax, (jmp_seg)
- lgdt gdtaddr_wakeup
- movl $0x008,%eax
- mov %eax,%ds
- movl %eax,%es
- movl %eax,%ss
- movl %eax,%fs
- movl %eax,%gs
- ljmp $0x0010,$reload_cs
- .code16gcc
-reload_cs:
- /* switch off PE */
+ movw %ax, (__wakeup_segment)
+
+ /* Then overwrite coreboot with our backed up memory */
+ movl 8(%esp), %esi
+ movl 12(%esp), %edi
+ movl 16(%esp), %ecx
+ shrl $4, %ecx
+1:
+ movl 0(%esi),%eax
+ movl 4(%esi),%edx
+ movl 8(%esi),%ebx
+ movl 12(%esi),%ebp
+ addl $16,%esi
+ subl $1,%ecx
+ movl %eax,0(%edi)
+ movl %edx,4(%edi)
+ movl %ebx,8(%edi)
+ movl %ebp,12(%edi)
+ leal 16(%edi),%edi
+ jne 1b
+
+ /* Activate the right segment descriptor real mode. */
+ ljmp $0x28, $RELOCATED(1f)
+1:
+.code16
+ /* 16 bit code from here on... */
+
+ /* Load the segment registers w/ properly configured
+ * segment descriptors. They will retain these
+ * configurations (limits, writability, etc.) once
+ * protected mode is turned off.
+ */
+ mov $0x30, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ /* Turn off protection */
movl %cr0, %eax
- andb $0xfe,%al
+ andl $~PE, %eax
movl %eax, %cr0
- ljmpl $0x0, $cpu_flushed
-cpu_flushed:
+
+ /* Now really going into real mode */
+ ljmp $0, $RELOCATED(1f)
+1:
movw $0x0, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
- /* far jump to OS waking vector. The linear addr is changed to SEG and OFFSET
- check ACPI specs or above code for details */
- .byte 0xea
-jmp_off:
- .word 0
-jmp_seg:
- .word 0
-.code32
-gdt_wakeup_limit = gdt_wakeup_end - gdt_wakeup - 1 /* compute the table limit */
- gdtaddr_wakeup:
- .word gdt_wakeup_limit /* the table limit */
- .long gdt_wakeup /* we know the offset */
-
- .data
-
- /* This is the gdt for GCC part of coreboot.
- * It is different from the gdt in ROMCC/ASM part of coreboot
- * which is defined in entry32.inc */
-gdt_wakeup:
- /* selgdt 0, unused */
- .word 0x0000, 0x0000 /* dummy */
- .byte 0x00, 0x00, 0x00, 0x00
+ /* This is a FAR JMP to the OS waking vector. The C code changed
+ * the address to be correct.
+ */
+ .byte 0xea
- /* selgdt 8, flat data segment 16bit */
- .word 0x0000, 0x0000 /* dummy */
- .byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
+__wakeup_offset = RELOCATED(.)
+ .word 0x0000
- /* selgdt 0x10, flat code segment 16bit */
- .word 0xffff, 0x0000
- .byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
+__wakeup_segment = RELOCATED(.)
+ .word 0x0000
-gdt_wakeup_end:
+ .globl __wakeup_size
+__wakeup_size = ( . - __wakeup)
- .previous
-.code32