1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * From coreboot src/arch/x86/wakeup.S 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+ 7*4882a593Smuzhiyun */ 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun#include <asm/acpi_s3.h> 10*4882a593Smuzhiyun#include <asm/processor.h> 11*4882a593Smuzhiyun#include <asm/processor-flags.h> 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun#define RELOCATED(x) ((x) - __wakeup + WAKEUP_BASE) 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun#define CODE_SEG (X86_GDT_ENTRY_16BIT_CS * X86_GDT_ENTRY_SIZE) 16*4882a593Smuzhiyun#define DATA_SEG (X86_GDT_ENTRY_16BIT_DS * X86_GDT_ENTRY_SIZE) 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun .code32 19*4882a593Smuzhiyun .globl __wakeup 20*4882a593Smuzhiyun__wakeup: 21*4882a593Smuzhiyun /* First prepare the jmp to the resume vector */ 22*4882a593Smuzhiyun mov 0x4(%esp), %eax /* vector */ 23*4882a593Smuzhiyun /* last 4 bits of linear addr are taken as offset */ 24*4882a593Smuzhiyun andw $0x0f, %ax 25*4882a593Smuzhiyun movw %ax, (__wakeup_offset) 26*4882a593Smuzhiyun mov 0x4(%esp), %eax 27*4882a593Smuzhiyun /* the rest is taken as segment */ 28*4882a593Smuzhiyun shr $4, %eax 29*4882a593Smuzhiyun movw %ax, (__wakeup_segment) 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun /* Activate the right segment descriptor real mode */ 32*4882a593Smuzhiyun ljmp $CODE_SEG, $RELOCATED(1f) 33*4882a593Smuzhiyun1: 34*4882a593Smuzhiyun /* 16 bit code from here on... */ 35*4882a593Smuzhiyun .code16 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun /* 38*4882a593Smuzhiyun * Load the segment registers w/ properly configured segment 39*4882a593Smuzhiyun * descriptors. They will retain these configurations (limits, 40*4882a593Smuzhiyun * writability, etc.) once protected mode is turned off. 41*4882a593Smuzhiyun */ 42*4882a593Smuzhiyun mov $DATA_SEG, %ax 43*4882a593Smuzhiyun mov %ax, %ds 44*4882a593Smuzhiyun mov %ax, %es 45*4882a593Smuzhiyun mov %ax, %fs 46*4882a593Smuzhiyun mov %ax, %gs 47*4882a593Smuzhiyun mov %ax, %ss 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun /* Turn off protection */ 50*4882a593Smuzhiyun movl %cr0, %eax 51*4882a593Smuzhiyun andl $~X86_CR0_PE, %eax 52*4882a593Smuzhiyun movl %eax, %cr0 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun /* Now really going into real mode */ 55*4882a593Smuzhiyun ljmp $0, $RELOCATED(1f) 56*4882a593Smuzhiyun1: 57*4882a593Smuzhiyun movw $0x0, %ax 58*4882a593Smuzhiyun movw %ax, %ds 59*4882a593Smuzhiyun movw %ax, %es 60*4882a593Smuzhiyun movw %ax, %ss 61*4882a593Smuzhiyun movw %ax, %fs 62*4882a593Smuzhiyun movw %ax, %gs 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun /* 65*4882a593Smuzhiyun * This is a FAR JMP to the OS waking vector. 66*4882a593Smuzhiyun * The C code changes the address to be correct. 67*4882a593Smuzhiyun */ 68*4882a593Smuzhiyun .byte 0xea 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun__wakeup_offset = RELOCATED(.) 71*4882a593Smuzhiyun .word 0x0000 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun__wakeup_segment = RELOCATED(.) 74*4882a593Smuzhiyun .word 0x0000 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun .globl __wakeup_size 77*4882a593Smuzhiyun__wakeup_size: 78*4882a593Smuzhiyun .long . - __wakeup 79