xref: /OK3568_Linux_fs/kernel/arch/x86/power/hibernate_asm_32.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * This may not use any stack, nor any variable that is not "NoSave":
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Its rewriting one kernel image with another. What is stack in "old"
6*4882a593Smuzhiyun * image could very well be data page in "new" image, and overwriting
7*4882a593Smuzhiyun * your own stack under you is bad idea.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun#include <linux/linkage.h>
11*4882a593Smuzhiyun#include <asm/segment.h>
12*4882a593Smuzhiyun#include <asm/page_types.h>
13*4882a593Smuzhiyun#include <asm/asm-offsets.h>
14*4882a593Smuzhiyun#include <asm/processor-flags.h>
15*4882a593Smuzhiyun#include <asm/frame.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun.text
18*4882a593Smuzhiyun
19*4882a593SmuzhiyunSYM_FUNC_START(swsusp_arch_suspend)
20*4882a593Smuzhiyun	movl %esp, saved_context_esp
21*4882a593Smuzhiyun	movl %ebx, saved_context_ebx
22*4882a593Smuzhiyun	movl %ebp, saved_context_ebp
23*4882a593Smuzhiyun	movl %esi, saved_context_esi
24*4882a593Smuzhiyun	movl %edi, saved_context_edi
25*4882a593Smuzhiyun	pushfl
26*4882a593Smuzhiyun	popl saved_context_eflags
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun	/* save cr3 */
29*4882a593Smuzhiyun	movl	%cr3, %eax
30*4882a593Smuzhiyun	movl	%eax, restore_cr3
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun	FRAME_BEGIN
33*4882a593Smuzhiyun	call swsusp_save
34*4882a593Smuzhiyun	FRAME_END
35*4882a593Smuzhiyun	RET
36*4882a593SmuzhiyunSYM_FUNC_END(swsusp_arch_suspend)
37*4882a593Smuzhiyun
38*4882a593SmuzhiyunSYM_CODE_START(restore_image)
39*4882a593Smuzhiyun	/* prepare to jump to the image kernel */
40*4882a593Smuzhiyun	movl	restore_jump_address, %ebx
41*4882a593Smuzhiyun	movl	restore_cr3, %ebp
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun	movl	mmu_cr4_features, %ecx
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun	/* jump to relocated restore code */
46*4882a593Smuzhiyun	movl	relocated_restore_code, %eax
47*4882a593Smuzhiyun	jmpl	*%eax
48*4882a593SmuzhiyunSYM_CODE_END(restore_image)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun/* code below has been relocated to a safe page */
51*4882a593SmuzhiyunSYM_CODE_START(core_restore_code)
52*4882a593Smuzhiyun	movl	temp_pgt, %eax
53*4882a593Smuzhiyun	movl	%eax, %cr3
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun	jecxz	1f	# cr4 Pentium and higher, skip if zero
56*4882a593Smuzhiyun	andl	$~(X86_CR4_PGE), %ecx
57*4882a593Smuzhiyun	movl	%ecx, %cr4;  # turn off PGE
58*4882a593Smuzhiyun	movl	%cr3, %eax;  # flush TLB
59*4882a593Smuzhiyun	movl	%eax, %cr3
60*4882a593Smuzhiyun1:
61*4882a593Smuzhiyun	movl	restore_pblist, %edx
62*4882a593Smuzhiyun	.p2align 4,,7
63*4882a593Smuzhiyun
64*4882a593Smuzhiyuncopy_loop:
65*4882a593Smuzhiyun	testl	%edx, %edx
66*4882a593Smuzhiyun	jz	done
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun	movl	pbe_address(%edx), %esi
69*4882a593Smuzhiyun	movl	pbe_orig_address(%edx), %edi
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun	movl	$(PAGE_SIZE >> 2), %ecx
72*4882a593Smuzhiyun	rep
73*4882a593Smuzhiyun	movsl
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun	movl	pbe_next(%edx), %edx
76*4882a593Smuzhiyun	jmp	copy_loop
77*4882a593Smuzhiyun	.p2align 4,,7
78*4882a593Smuzhiyun
79*4882a593Smuzhiyundone:
80*4882a593Smuzhiyun	jmpl	*%ebx
81*4882a593SmuzhiyunSYM_CODE_END(core_restore_code)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun	/* code below belongs to the image kernel */
84*4882a593Smuzhiyun	.align PAGE_SIZE
85*4882a593SmuzhiyunSYM_FUNC_START(restore_registers)
86*4882a593Smuzhiyun	/* go back to the original page tables */
87*4882a593Smuzhiyun	movl	%ebp, %cr3
88*4882a593Smuzhiyun	movl	mmu_cr4_features, %ecx
89*4882a593Smuzhiyun	jecxz	1f	# cr4 Pentium and higher, skip if zero
90*4882a593Smuzhiyun	movl	%ecx, %cr4;  # turn PGE back on
91*4882a593Smuzhiyun1:
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun	movl saved_context_esp, %esp
94*4882a593Smuzhiyun	movl saved_context_ebp, %ebp
95*4882a593Smuzhiyun	movl saved_context_ebx, %ebx
96*4882a593Smuzhiyun	movl saved_context_esi, %esi
97*4882a593Smuzhiyun	movl saved_context_edi, %edi
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun	pushl saved_context_eflags
100*4882a593Smuzhiyun	popfl
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun	/* Saved in save_processor_state. */
103*4882a593Smuzhiyun	movl $saved_context, %eax
104*4882a593Smuzhiyun	lgdt saved_context_gdt_desc(%eax)
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun	xorl	%eax, %eax
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun	/* tell the hibernation core that we've just restored the memory */
109*4882a593Smuzhiyun	movl	%eax, in_suspend
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun	RET
112*4882a593SmuzhiyunSYM_FUNC_END(restore_registers)
113