1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */ 2c5759124SRafael J. Wysocki/* 3c5759124SRafael J. Wysocki * This may not use any stack, nor any variable that is not "NoSave": 4c5759124SRafael J. Wysocki * 5c5759124SRafael J. Wysocki * Its rewriting one kernel image with another. What is stack in "old" 6c5759124SRafael J. Wysocki * image could very well be data page in "new" image, and overwriting 7c5759124SRafael J. Wysocki * your own stack under you is bad idea. 8c5759124SRafael J. Wysocki */ 9c5759124SRafael J. Wysocki 10c5759124SRafael J. Wysocki#include <linux/linkage.h> 11c5759124SRafael J. Wysocki#include <asm/segment.h> 120341c14dSJeremy Fitzhardinge#include <asm/page_types.h> 13c5759124SRafael J. Wysocki#include <asm/asm-offsets.h> 14c171f465SUros Bizjak#include <asm/processor-flags.h> 158e5b2a3cSZhimin Gu#include <asm/frame.h> 16c5759124SRafael J. Wysocki 17c5759124SRafael J. Wysocki.text 18c5759124SRafael J. Wysocki 196d685e53SJiri SlabySYM_FUNC_START(swsusp_arch_suspend) 20c5759124SRafael J. Wysocki movl %esp, saved_context_esp 21c5759124SRafael J. Wysocki movl %ebx, saved_context_ebx 22c5759124SRafael J. Wysocki movl %ebp, saved_context_ebp 23c5759124SRafael J. Wysocki movl %esi, saved_context_esi 24c5759124SRafael J. Wysocki movl %edi, saved_context_edi 25c171f465SUros Bizjak pushfl 26c171f465SUros Bizjak popl saved_context_eflags 27c5759124SRafael J. Wysocki 2832aa2764SZhimin Gu /* save cr3 */ 2932aa2764SZhimin Gu movl %cr3, %eax 3032aa2764SZhimin Gu movl %eax, restore_cr3 3132aa2764SZhimin Gu 328e5b2a3cSZhimin Gu FRAME_BEGIN 33c5759124SRafael J. Wysocki call swsusp_save 348e5b2a3cSZhimin Gu FRAME_END 35*f94909ceSPeter Zijlstra RET 366d685e53SJiri SlabySYM_FUNC_END(swsusp_arch_suspend) 37c5759124SRafael J. Wysocki 3878762b0eSJiri SlabySYM_CODE_START(restore_image) 395331d2c7SZhimin Gu /* prepare to jump to the image kernel */ 405331d2c7SZhimin Gu movl restore_jump_address, %ebx 4132aa2764SZhimin Gu movl restore_cr3, %ebp 4232aa2764SZhimin Gu 438ae06d22SShaohua Li movl mmu_cr4_features, %ecx 446bae499aSZhimin Gu 456bae499aSZhimin Gu /* jump to relocated restore code */ 466bae499aSZhimin Gu movl relocated_restore_code, %eax 476bae499aSZhimin Gu jmpl *%eax 4878762b0eSJiri SlabySYM_CODE_END(restore_image) 496bae499aSZhimin Gu 506bae499aSZhimin Gu/* code below has been relocated to a safe page */ 5178762b0eSJiri SlabySYM_CODE_START(core_restore_code) 527c0a9827SZhimin Gu movl temp_pgt, %eax 53e532c06fSDavid Fries movl %eax, %cr3 54c5759124SRafael J. Wysocki 558ae06d22SShaohua Li jecxz 1f # cr4 Pentium and higher, skip if zero 568ae06d22SShaohua Li andl $~(X86_CR4_PGE), %ecx 578ae06d22SShaohua Li movl %ecx, %cr4; # turn off PGE 588ae06d22SShaohua Li movl %cr3, %eax; # flush TLB 598ae06d22SShaohua Li movl %eax, %cr3 608ae06d22SShaohua Li1: 61c5759124SRafael J. Wysocki movl restore_pblist, %edx 62c5759124SRafael J. Wysocki .p2align 4,,7 63c5759124SRafael J. Wysocki 64c5759124SRafael J. Wysockicopy_loop: 65c5759124SRafael J. Wysocki testl %edx, %edx 66c5759124SRafael J. Wysocki jz done 67c5759124SRafael J. Wysocki 68c5759124SRafael J. Wysocki movl pbe_address(%edx), %esi 69c5759124SRafael J. Wysocki movl pbe_orig_address(%edx), %edi 70c5759124SRafael J. Wysocki 710b0a6b1fSZhimin Gu movl $(PAGE_SIZE >> 2), %ecx 72c5759124SRafael J. Wysocki rep 73c5759124SRafael J. Wysocki movsl 74c5759124SRafael J. Wysocki 75c5759124SRafael J. Wysocki movl pbe_next(%edx), %edx 76c5759124SRafael J. Wysocki jmp copy_loop 77c5759124SRafael J. Wysocki .p2align 4,,7 78c5759124SRafael J. Wysocki 79c5759124SRafael J. Wysockidone: 805331d2c7SZhimin Gu jmpl *%ebx 8178762b0eSJiri SlabySYM_CODE_END(core_restore_code) 828e5b2a3cSZhimin Gu 838e5b2a3cSZhimin Gu /* code below belongs to the image kernel */ 848e5b2a3cSZhimin Gu .align PAGE_SIZE 856d685e53SJiri SlabySYM_FUNC_START(restore_registers) 86c5759124SRafael J. Wysocki /* go back to the original page tables */ 8732aa2764SZhimin Gu movl %ebp, %cr3 88e532c06fSDavid Fries movl mmu_cr4_features, %ecx 89e532c06fSDavid Fries jecxz 1f # cr4 Pentium and higher, skip if zero 90e532c06fSDavid Fries movl %ecx, %cr4; # turn PGE back on 91e532c06fSDavid Fries1: 92c5759124SRafael J. Wysocki 93c5759124SRafael J. Wysocki movl saved_context_esp, %esp 94c5759124SRafael J. Wysocki movl saved_context_ebp, %ebp 95c5759124SRafael J. Wysocki movl saved_context_ebx, %ebx 96c5759124SRafael J. Wysocki movl saved_context_esi, %esi 97c5759124SRafael J. Wysocki movl saved_context_edi, %edi 98c5759124SRafael J. Wysocki 99c171f465SUros Bizjak pushl saved_context_eflags 100c171f465SUros Bizjak popfl 101c5759124SRafael J. Wysocki 102cc456c4eSKonrad Rzeszutek Wilk /* Saved in save_processor_state. */ 103cc456c4eSKonrad Rzeszutek Wilk movl $saved_context, %eax 104cc456c4eSKonrad Rzeszutek Wilk lgdt saved_context_gdt_desc(%eax) 105cc456c4eSKonrad Rzeszutek Wilk 106c5759124SRafael J. Wysocki xorl %eax, %eax 107c5759124SRafael J. Wysocki 1081fca4ba0SZhimin Gu /* tell the hibernation core that we've just restored the memory */ 1091fca4ba0SZhimin Gu movl %eax, in_suspend 1101fca4ba0SZhimin Gu 111*f94909ceSPeter Zijlstra RET 1126d685e53SJiri SlabySYM_FUNC_END(restore_registers) 113