Patrick Georgi | 11f0079 | 2020-03-04 15:10:45 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 2 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 3 | #define WAKEUP_BASE 0x600 |
| 4 | #define RELOCATED(x) (x - __wakeup + WAKEUP_BASE) |
| 5 | |
| 6 | /* CR0 bits */ |
| 7 | #define PE (1 << 0) |
| 8 | |
Stefan Reinauer | 9693885 | 2015-06-18 01:23:48 -0700 | [diff] [blame] | 9 | #ifdef __x86_64__ |
| 10 | .code64 |
| 11 | #else |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 12 | .code32 |
Stefan Reinauer | 9693885 | 2015-06-18 01:23:48 -0700 | [diff] [blame] | 13 | #endif |
| 14 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 15 | .globl __wakeup |
| 16 | __wakeup: |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 17 | #ifdef __x86_64__ |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 18 | xor %rax,%rax |
| 19 | mov %ss, %ax |
| 20 | push %rax |
| 21 | mov %rsp, %rax |
| 22 | add $8, %rax |
| 23 | push %rax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 24 | pushfq |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 25 | push $0x10 |
| 26 | lea 3(%rip), %rax |
| 27 | push %rax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 28 | iretq |
| 29 | |
| 30 | .code32 |
| 31 | |
| 32 | /* disable paging */ |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 33 | mov %cr0, %eax |
| 34 | btc $31, %eax |
| 35 | mov %eax, %cr0 |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 36 | |
| 37 | /* disable long mode */ |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 38 | mov $0xC0000080, %ecx |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 39 | rdmsr |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 40 | btc $8, %eax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 41 | wrmsr |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 42 | #endif |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 43 | /* First prepare the jmp to the resume vector */ |
| 44 | mov 0x4(%esp), %eax /* vector */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 45 | /* last 4 bits of linear addr are taken as offset */ |
| 46 | andw $0x0f, %ax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 47 | movw %ax, (__wakeup_offset) |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 48 | mov 0x4(%esp), %eax |
| 49 | /* the rest is taken as segment */ |
| 50 | shr $4, %eax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 51 | movw %ax, (__wakeup_segment) |
| 52 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 53 | /* Activate the right segment descriptor real mode. */ |
| 54 | ljmp $0x28, $RELOCATED(1f) |
| 55 | 1: |
| 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 65 | mov %ax, %ds |
| 66 | mov %ax, %es |
| 67 | mov %ax, %fs |
| 68 | mov %ax, %gs |
| 69 | mov %ax, %ss |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 70 | |
| 71 | /* Turn off protection */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 72 | movl %cr0, %eax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 73 | andl $~PE, %eax |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 74 | movl %eax, %cr0 |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 75 | |
| 76 | /* Now really going into real mode */ |
| 77 | ljmp $0, $RELOCATED(1f) |
| 78 | 1: |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 79 | movw $0x0, %ax |
| 80 | movw %ax, %ds |
| 81 | movw %ax, %es |
| 82 | movw %ax, %ss |
| 83 | movw %ax, %fs |
| 84 | movw %ax, %gs |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 85 | |
| 86 | /* This is a FAR JMP to the OS waking vector. The C code changed |
| 87 | * the address to be correct. |
| 88 | */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 89 | .byte 0xea |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 90 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 91 | __wakeup_offset = RELOCATED(.) |
| 92 | .word 0x0000 |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 93 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 94 | __wakeup_segment = RELOCATED(.) |
| 95 | .word 0x0000 |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 96 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 97 | .globl __wakeup_size |
Aaron Durbin | a146d58 | 2013-02-08 16:56:51 -0600 | [diff] [blame] | 98 | __wakeup_size: |
| 99 | .long . - __wakeup |