a1df4d5597700ce8b0dd0d591f94a4ea42973232
[coreboot.git] / src / arch / x86 / boot / wakeup.S
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
5  * Copyright (C) 2009 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #define WAKEUP_BASE             0x600
22 #define RELOCATED(x)    (x - __wakeup + WAKEUP_BASE)
23
24 /* CR0 bits */
25 #define PE              (1 << 0)
26
27         .code32
28         .globl __wakeup
29 __wakeup:
30         /* First prepare the jmp to the resume vector */
31         mov     0x4(%esp), %eax /* vector */
32         /* last 4 bits of linear addr are taken as offset */
33         andw    $0x0f, %ax
34         movw    %ax, (__wakeup_offset)
35         mov     0x4(%esp), %eax
36         /* the rest is taken as segment */
37         shr     $4, %eax
38         movw    %ax, (__wakeup_segment)
39
40         /* Then overwrite coreboot with our backed up memory */
41         movl 8(%esp), %esi
42         movl 12(%esp), %edi
43         movl 16(%esp), %ecx
44         shrl    $4, %ecx
45 1:
46         movl    0(%esi),%eax
47         movl    4(%esi),%edx
48         movl    8(%esi),%ebx
49         movl    12(%esi),%ebp
50         addl    $16,%esi
51         subl    $1,%ecx
52         movl    %eax,0(%edi)
53         movl    %edx,4(%edi)
54         movl    %ebx,8(%edi)
55         movl    %ebp,12(%edi)
56         leal    16(%edi),%edi
57         jne     1b
58
59         /* Activate the right segment descriptor real mode. */
60         ljmp    $0x28, $RELOCATED(1f)
61 1:
62 .code16
63         /* 16 bit code from here on... */
64
65         /* Load the segment registers w/ properly configured
66          * segment descriptors. They will retain these
67          * configurations (limits, writability, etc.) once
68          * protected mode is turned off.
69          */
70         mov     $0x30, %ax
71         mov     %ax, %ds
72         mov     %ax, %es
73         mov     %ax, %fs
74         mov     %ax, %gs
75         mov     %ax, %ss
76
77         /* Turn off protection */
78         movl    %cr0, %eax
79         andl    $~PE, %eax
80         movl    %eax, %cr0
81
82         /* Now really going into real mode */
83         ljmp    $0, $RELOCATED(1f)
84 1:
85         movw    $0x0, %ax
86         movw    %ax, %ds
87         movw    %ax, %es
88         movw    %ax, %ss
89         movw    %ax, %fs
90         movw    %ax, %gs
91
92         /* This is a FAR JMP to the OS waking vector. The C code changed
93          * the address to be correct.
94          */
95         .byte 0xea
96
97 __wakeup_offset = RELOCATED(.)
98         .word 0x0000
99
100 __wakeup_segment = RELOCATED(.)
101         .word 0x0000
102
103         .globl __wakeup_size
104 __wakeup_size = ( . - __wakeup)
105