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