summaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/acpi/wakeup_32.S
blob: cf69081073b5414700b926761180b68df5cfd6a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* SPDX-License-Identifier: GPL-2.0-only */
	.text
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page_types.h>

# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz

	.code32
	ALIGN

SYM_CODE_START(wakeup_pmode_return)
	movw	$__KERNEL_DS, %ax
	movw	%ax, %ss
	movw	%ax, %fs
	movw	%ax, %gs

	movw	$__USER_DS, %ax
	movw	%ax, %ds
	movw	%ax, %es

	# reload the gdt, as we need the full 32 bit address
	lidt	saved_idt
	lldt	saved_ldt
	ljmp	$(__KERNEL_CS), $1f
1:
	movl	%cr3, %eax
	movl	%eax, %cr3
	wbinvd

	# and restore the stack ... but you need gdt for this to work
	movl	saved_context_esp, %esp

	movl	%cs:saved_magic, %eax
	cmpl	$0x12345678, %eax
	jne	bogus_magic

	# jump to place where we left off
	movl	saved_eip, %eax
	jmp	*%eax
SYM_CODE_END(wakeup_pmode_return)

bogus_magic:
	jmp	bogus_magic



save_registers:
	sidt	saved_idt
	sldt	saved_ldt
	str	saved_tss

	leal	4(%esp), %eax
	movl	%eax, saved_context_esp
	movl	%ebx, saved_context_ebx
	movl	%ebp, saved_context_ebp
	movl	%esi, saved_context_esi
	movl	%edi, saved_context_edi
	pushfl
	popl	saved_context_eflags

	movl	$ret_point, saved_eip
	RET


restore_registers:
	movl	saved_context_ebp, %ebp
	movl	saved_context_ebx, %ebx
	movl	saved_context_esi, %esi
	movl	saved_context_edi, %edi
	pushl	saved_context_eflags
	popfl
	RET

SYM_CODE_START(do_suspend_lowlevel)
	call	save_processor_state
	call	save_registers
	pushl	$3
	call	x86_acpi_enter_sleep_state
	addl	$4, %esp

#	In case of S3 failure, we'll emerge here.  Jump
# 	to ret_point to recover
	jmp	ret_point
	.p2align 4,,7
ret_point:
	call	restore_registers
	call	restore_processor_state
	RET
SYM_CODE_END(do_suspend_lowlevel)

.data
ALIGN
SYM_DATA(saved_magic,	.long 0)
saved_eip:		.long 0

# saved registers
saved_idt:	.long	0,0
saved_ldt:	.long	0
saved_tss:	.long	0