xref: /OK3568_Linux_fs/u-boot/arch/x86/cpu/wakeup.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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