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