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