blob: ae2efe00edf388db2625c9158e4c4fa794dc0f2e [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Rudolf Marek33cafe52009-04-13 18:07:02 +00002
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +00003#define WAKEUP_BASE 0x600
4#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE)
5
6/* CR0 bits */
7#define PE (1 << 0)
8
Stefan Reinauer96938852015-06-18 01:23:48 -07009#ifdef __x86_64__
10 .code64
11#else
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000012 .code32
Stefan Reinauer96938852015-06-18 01:23:48 -070013#endif
14
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000015 .globl __wakeup
16__wakeup:
Stefan Reinauerac901e62015-07-31 16:46:28 -070017#ifdef __x86_64__
Elyes HAOUAS2397baf2018-12-22 09:47:46 +010018 xor %rax,%rax
19 mov %ss, %ax
20 push %rax
21 mov %rsp, %rax
22 add $8, %rax
23 push %rax
Stefan Reinauerac901e62015-07-31 16:46:28 -070024 pushfq
Elyes HAOUAS2397baf2018-12-22 09:47:46 +010025 push $0x10
26 lea 3(%rip), %rax
27 push %rax
Stefan Reinauerac901e62015-07-31 16:46:28 -070028 iretq
29
30 .code32
31
32 /* disable paging */
Elyes HAOUAS2397baf2018-12-22 09:47:46 +010033 mov %cr0, %eax
34 btc $31, %eax
35 mov %eax, %cr0
Stefan Reinauerac901e62015-07-31 16:46:28 -070036
37 /* disable long mode */
Elyes HAOUAS2397baf2018-12-22 09:47:46 +010038 mov $0xC0000080, %ecx
Stefan Reinauerac901e62015-07-31 16:46:28 -070039 rdmsr
Elyes HAOUAS2397baf2018-12-22 09:47:46 +010040 btc $8, %eax
Stefan Reinauerac901e62015-07-31 16:46:28 -070041 wrmsr
Stefan Reinauerac901e62015-07-31 16:46:28 -070042#endif
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000043 /* First prepare the jmp to the resume vector */
44 mov 0x4(%esp), %eax /* vector */
Rudolf Marek33cafe52009-04-13 18:07:02 +000045 /* last 4 bits of linear addr are taken as offset */
46 andw $0x0f, %ax
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000047 movw %ax, (__wakeup_offset)
Rudolf Marek33cafe52009-04-13 18:07:02 +000048 mov 0x4(%esp), %eax
49 /* the rest is taken as segment */
50 shr $4, %eax
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000051 movw %ax, (__wakeup_segment)
52
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000053 /* Activate the right segment descriptor real mode. */
54 ljmp $0x28, $RELOCATED(1f)
551:
56.code16
57 /* 16 bit code from here on... */
58
59 /* Load the segment registers w/ properly configured
60 * segment descriptors. They will retain these
61 * configurations (limits, writability, etc.) once
62 * protected mode is turned off.
63 */
64 mov $0x30, %ax
Stefan Reinauer14e22772010-04-27 06:56:47 +000065 mov %ax, %ds
66 mov %ax, %es
67 mov %ax, %fs
68 mov %ax, %gs
69 mov %ax, %ss
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000070
71 /* Turn off protection */
Rudolf Marek33cafe52009-04-13 18:07:02 +000072 movl %cr0, %eax
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000073 andl $~PE, %eax
Rudolf Marek33cafe52009-04-13 18:07:02 +000074 movl %eax, %cr0
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000075
76 /* Now really going into real mode */
77 ljmp $0, $RELOCATED(1f)
781:
Rudolf Marek33cafe52009-04-13 18:07:02 +000079 movw $0x0, %ax
80 movw %ax, %ds
81 movw %ax, %es
82 movw %ax, %ss
83 movw %ax, %fs
84 movw %ax, %gs
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000085
86 /* This is a FAR JMP to the OS waking vector. The C code changed
87 * the address to be correct.
88 */
Rudolf Marek33cafe52009-04-13 18:07:02 +000089 .byte 0xea
Rudolf Marek33cafe52009-04-13 18:07:02 +000090
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000091__wakeup_offset = RELOCATED(.)
92 .word 0x0000
Rudolf Marek33cafe52009-04-13 18:07:02 +000093
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000094__wakeup_segment = RELOCATED(.)
95 .word 0x0000
Rudolf Marek33cafe52009-04-13 18:07:02 +000096
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000097 .globl __wakeup_size
Aaron Durbina146d582013-02-08 16:56:51 -060098__wakeup_size:
99 .long . - __wakeup