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