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 | |
Patrick Rudolph | adcf782 | 2020-08-27 20:50:18 +0200 | [diff] [blame] | 9 | #if ENV_X86_64 |
Stefan Reinauer | 9693885 | 2015-06-18 01:23:48 -0700 | [diff] [blame] | 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: |
Patrick Rudolph | adcf782 | 2020-08-27 20:50:18 +0200 | [diff] [blame] | 17 | #if ENV_X86_64 |
Iru Cai | 88eb167 | 2021-06-29 21:16:26 +0800 | [diff] [blame] | 18 | /* When called in x86_64 mode, the resume vector is in %rdi |
| 19 | * instead of the stack, save it in 4(%rsp) for the 32-bit code. |
| 20 | * It's OK to overwrite the return address at (%rsp) because this |
| 21 | * function doesn't return. |
| 22 | */ |
| 23 | mov %edi, 4(%rsp) |
| 24 | |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 25 | xor %rax,%rax |
| 26 | mov %ss, %ax |
| 27 | push %rax |
| 28 | mov %rsp, %rax |
| 29 | add $8, %rax |
| 30 | push %rax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 31 | pushfq |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 32 | push $0x10 |
| 33 | lea 3(%rip), %rax |
| 34 | push %rax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 35 | iretq |
| 36 | |
| 37 | .code32 |
| 38 | |
| 39 | /* disable paging */ |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 40 | mov %cr0, %eax |
| 41 | btc $31, %eax |
| 42 | mov %eax, %cr0 |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 43 | |
| 44 | /* disable long mode */ |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 45 | mov $0xC0000080, %ecx |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 46 | rdmsr |
Elyes HAOUAS | 2397baf | 2018-12-22 09:47:46 +0100 | [diff] [blame] | 47 | btc $8, %eax |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 48 | wrmsr |
Stefan Reinauer | ac901e6 | 2015-07-31 16:46:28 -0700 | [diff] [blame] | 49 | #endif |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 50 | /* First prepare the jmp to the resume vector */ |
| 51 | mov 0x4(%esp), %eax /* vector */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 52 | /* last 4 bits of linear addr are taken as offset */ |
| 53 | andw $0x0f, %ax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 54 | movw %ax, (__wakeup_offset) |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 55 | mov 0x4(%esp), %eax |
| 56 | /* the rest is taken as segment */ |
| 57 | shr $4, %eax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 58 | movw %ax, (__wakeup_segment) |
| 59 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 60 | /* Activate the right segment descriptor real mode. */ |
| 61 | ljmp $0x28, $RELOCATED(1f) |
| 62 | 1: |
| 63 | .code16 |
| 64 | /* 16 bit code from here on... */ |
| 65 | |
| 66 | /* Load the segment registers w/ properly configured |
| 67 | * segment descriptors. They will retain these |
| 68 | * configurations (limits, writability, etc.) once |
| 69 | * protected mode is turned off. |
| 70 | */ |
| 71 | mov $0x30, %ax |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 72 | mov %ax, %ds |
| 73 | mov %ax, %es |
| 74 | mov %ax, %fs |
| 75 | mov %ax, %gs |
| 76 | mov %ax, %ss |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 77 | |
| 78 | /* Turn off protection */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 79 | movl %cr0, %eax |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 80 | andl $~PE, %eax |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 81 | movl %eax, %cr0 |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 82 | |
| 83 | /* Now really going into real mode */ |
| 84 | ljmp $0, $RELOCATED(1f) |
| 85 | 1: |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 86 | movw $0x0, %ax |
| 87 | movw %ax, %ds |
| 88 | movw %ax, %es |
| 89 | movw %ax, %ss |
| 90 | movw %ax, %fs |
| 91 | movw %ax, %gs |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 92 | |
| 93 | /* This is a FAR JMP to the OS waking vector. The C code changed |
| 94 | * the address to be correct. |
| 95 | */ |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 96 | .byte 0xea |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 97 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 98 | __wakeup_offset = RELOCATED(.) |
| 99 | .word 0x0000 |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 100 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 101 | __wakeup_segment = RELOCATED(.) |
| 102 | .word 0x0000 |
Rudolf Marek | 33cafe5 | 2009-04-13 18:07:02 +0000 | [diff] [blame] | 103 | |
Stefan Reinauer | c0ac7e9 | 2009-11-10 22:17:15 +0000 | [diff] [blame] | 104 | .globl __wakeup_size |
Aaron Durbin | a146d58 | 2013-02-08 16:56:51 -0600 | [diff] [blame] | 105 | __wakeup_size: |
| 106 | .long . - __wakeup |