cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wakeup_asm.S (3864B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * ACPI wakeup real mode startup stub
      4 */
      5#include <linux/linkage.h>
      6#include <asm/segment.h>
      7#include <asm/msr-index.h>
      8#include <asm/page_types.h>
      9#include <asm/pgtable_types.h>
     10#include <asm/processor-flags.h>
     11#include "realmode.h"
     12#include "wakeup.h"
     13
     14	.code16
     15
     16/* This should match the structure in wakeup.h */
     17	.section ".data", "aw"
     18
     19	.balign	16
     20SYM_DATA_START(wakeup_header)
     21	video_mode:	.short	0	/* Video mode number */
     22	pmode_entry:	.long	0
     23	pmode_cs:	.short	__KERNEL_CS
     24	pmode_cr0:	.long	0	/* Saved %cr0 */
     25	pmode_cr3:	.long	0	/* Saved %cr3 */
     26	pmode_cr4:	.long	0	/* Saved %cr4 */
     27	pmode_efer:	.quad	0	/* Saved EFER */
     28	pmode_gdt:	.quad	0
     29	pmode_misc_en:	.quad	0	/* Saved MISC_ENABLE MSR */
     30	pmode_behavior:	.long	0	/* Wakeup behavior flags */
     31	realmode_flags:	.long	0
     32	real_magic:	.long	0
     33	signature:	.long	WAKEUP_HEADER_SIGNATURE
     34SYM_DATA_END(wakeup_header)
     35
     36	.text
     37	.code16
     38
     39	.balign	16
     40SYM_CODE_START(wakeup_start)
     41	cli
     42	cld
     43
     44	LJMPW_RM(3f)
     453:
     46	/* Apparently some dimwit BIOS programmers don't know how to
     47	   program a PM to RM transition, and we might end up here with
     48	   junk in the data segment descriptor registers.  The only way
     49	   to repair that is to go into PM and fix it ourselves... */
     50	movw	$16, %cx
     51	lgdtl	%cs:wakeup_gdt
     52	movl	%cr0, %eax
     53	orb	$X86_CR0_PE, %al
     54	movl	%eax, %cr0
     55	ljmpw	$8, $2f
     562:
     57	movw	%cx, %ds
     58	movw	%cx, %es
     59	movw	%cx, %ss
     60	movw	%cx, %fs
     61	movw	%cx, %gs
     62
     63	andb	$~X86_CR0_PE, %al
     64	movl	%eax, %cr0
     65	LJMPW_RM(3f)
     663:
     67	/* Set up segments */
     68	movw	%cs, %ax
     69	movw	%ax, %ss
     70	movl	$rm_stack_end, %esp
     71	movw	%ax, %ds
     72	movw	%ax, %es
     73	movw	%ax, %fs
     74	movw	%ax, %gs
     75
     76	lidtl	.Lwakeup_idt
     77
     78	/* Clear the EFLAGS */
     79	pushl $0
     80	popfl
     81
     82	/* Check header signature... */
     83	movl	signature, %eax
     84	cmpl	$WAKEUP_HEADER_SIGNATURE, %eax
     85	jne	bogus_real_magic
     86
     87	/* Check we really have everything... */
     88	movl	end_signature, %eax
     89	cmpl	$REALMODE_END_SIGNATURE, %eax
     90	jne	bogus_real_magic
     91
     92	/* Call the C code */
     93	calll	main
     94
     95	/* Restore MISC_ENABLE before entering protected mode, in case
     96	   BIOS decided to clear XD_DISABLE during S3. */
     97	movl	pmode_behavior, %edi
     98	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
     99	jnc	1f
    100
    101	movl	pmode_misc_en, %eax
    102	movl	pmode_misc_en + 4, %edx
    103	movl	$MSR_IA32_MISC_ENABLE, %ecx
    104	wrmsr
    1051:
    106
    107	/* Do any other stuff... */
    108
    109#ifndef CONFIG_64BIT
    110	/* This could also be done in C code... */
    111	movl	pmode_cr3, %eax
    112	movl	%eax, %cr3
    113
    114	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
    115	jnc	1f
    116	movl	pmode_cr4, %eax
    117	movl	%eax, %cr4
    1181:
    119	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
    120	jnc	1f
    121	movl	pmode_efer, %eax
    122	movl	pmode_efer + 4, %edx
    123	movl	$MSR_EFER, %ecx
    124	wrmsr
    1251:
    126
    127	lgdtl	pmode_gdt
    128
    129	/* This really couldn't... */
    130	movl	pmode_entry, %eax
    131	movl	pmode_cr0, %ecx
    132	movl	%ecx, %cr0
    133	ljmpl	$__KERNEL_CS, $pa_startup_32
    134	/* -> jmp *%eax in trampoline_32.S */
    135#else
    136	jmp	trampoline_start
    137#endif
    138SYM_CODE_END(wakeup_start)
    139
    140bogus_real_magic:
    1411:
    142	hlt
    143	jmp	1b
    144
    145	.section ".rodata","a"
    146
    147	/*
    148	 * Set up the wakeup GDT.  We set these up as Big Real Mode,
    149	 * that is, with limits set to 4 GB.  At least the Lenovo
    150	 * Thinkpad X61 is known to need this for the video BIOS
    151	 * initialization quirk to work; this is likely to also
    152	 * be the case for other laptops or integrated video devices.
    153	 */
    154
    155	.balign	16
    156SYM_DATA_START(wakeup_gdt)
    157	.word	3*8-1		/* Self-descriptor */
    158	.long	pa_wakeup_gdt
    159	.word	0
    160
    161	.word	0xffff		/* 16-bit code segment @ real_mode_base */
    162	.long	0x9b000000 + pa_real_mode_base
    163	.word	0x008f		/* big real mode */
    164
    165	.word	0xffff		/* 16-bit data segment @ real_mode_base */
    166	.long	0x93000000 + pa_real_mode_base
    167	.word	0x008f		/* big real mode */
    168SYM_DATA_END(wakeup_gdt)
    169
    170	.section ".rodata","a"
    171	.balign	8
    172
    173	/* This is the standard real-mode IDT */
    174	.balign	16
    175SYM_DATA_START_LOCAL(.Lwakeup_idt)
    176	.word	0xffff		/* limit */
    177	.long	0		/* address */
    178	.word	0
    179SYM_DATA_END(.Lwakeup_idt)