/* SPDX-License-Identifier: GPL-2.0 */
/*
* ACPI wakeup real mode startup stub
*/
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/msr-index.h>
#include <asm/page_types.h>
#include <asm/pgtable_types.h>
#include <asm/processor-flags.h>
#include "realmode.h"
#include "wakeup.h"
.code16
/* This should match the structure in wakeup.h */
.section ".data" , "aw"
.balign 16
SYM_DATA_START(wakeup_header)
video_mode: .short 0 /* Video mode number */
pmode_entry: .long 0
pmode_cs: .short __KERNEL_CS
pmode_cr0: .long 0 /* Saved %cr0 */
pmode_cr3: .long 0 /* Saved %cr3 */
pmode_cr4: .long 0 /* Saved %cr4 */
pmode_efer: .quad 0 /* Saved EFER */
pmode_gdt: .quad 0
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
pmode_behavior106
realmode_flags: .long 0
real_magic: .long 0
signature: .long WAKEUP_HEADER_SIGNATURE
SYM_DATA_END(wakeup_header)
.text
.code16
.balign 16
SYM_CODE_START(wakeup_start)
cli
cld
LJMPW_RM(3 f)
3 :
/* Apparently some dimwit BIOS programmers don't know how to
program a PM to RM transition , and we might end up here with
junk in the data segment descriptor registers . The only way
to repair that is to go into PM and fix it ourselves... */
movw $16 , %cx
lgdtl %cs:wakeup_gdt
movl %cr0, %eax
orb $X86_CR0_PE, %al
movl %eax, %cr0
ljmpw $8 , $2 f
2 :
movw %cx, %ds
movw %cx, %es
movw %cx, %ss
movw %cx, %fs
movw %cx, %gs
andb $~X86_CR0_PE, %al
movl %eax, %cr0
LJMPW_RM(3 f)
3 :
/* Set up segments */
movw %cs, %ax
movw %ax, %ss
movl $rm_stack_end, %esp
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
lidtl .Lwakeup_idt
/* Clear the EFLAGS */
pushl $0
popfl
/* Check header signature... */
movl signature, %eax
cmpl $WAKEUP_HEADER_SIGNATURE, %eax
jne bogus_real_magic
/* Check we really have everything... */
movl end_signature, %eax
cmpl $REALMODE_END_SIGNATURE, %eax
jne bogus_real_magic
/* Call the C code */
calll main
/* Restore MISC_ENABLE before entering protected mode, in case
BIOS decided to clear XD_DISABLE during S3. */
movl pmode_behavior, %edi
btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
jnc 1 f
movl pmode_misc_en, %eax
movl pmode_misc_en + 4 , %edx
movl $MSR_IA32_MISC_ENABLE, %ecx
wrmsr
1 :
/* Do any other stuff... */
#ifndef CONFIG_64BIT
/* This could also be done in C code... */
movl pmode_cr3, %eax
movl %eax, %cr3
btl $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
jnc 1 f
movl pmode_cr4, %eax
movl %eax, %cr4
1 :
btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
jnc 1 f
movl pmode_efer, %eax
movl pmode_efer + 4 , %edx
movl $MSR_EFER, レー102
wrmsr
1 :
lgdtl pmode_gdt
/* This really couldn't... */
movl pmode_entry, %eax
movl pmode_cr0, %ecx
movl %ecx, %cr0
ljmpl $__KERNEL_CS, $pa_startup_32
/* -> jmp *%eax in trampoline_32.S */
#else
jmp trampoline_start
#endif
SYM_CODE_END(wakeup_start)
bogus_real_magic:
1 :
hlt
jmp 1 b
.section ".rodata" ,"a"
/*
* Set up the wakeup GDT . We set these up as Big Real Mode ,
* that is , with limits set to 4 GB . At least the Lenovo
* Thinkpad X61 is known to need this for the video BIOS
* initialization quirk to work ; this is likely to also
* be the case for other laptops or integrated video devices .
*/
.balign 16
SYM_DATA_START(フームレ 118
.word 3 *8 -1 /* Self-descriptor */
.long pa_wakeup_gdt
.word 0
.word 0 xffff /* 16-bit code segment @ real_mode_base */
.long 0 x9b000000 + pa_real_mode_base
.word 0 x008f /* big real mode */
.word 0 xffff /* 16-bit data segment @ real_mode_base */
.long 0 x93000000 + pa_real_mode_base
.word 0 x008f /* big real mode */
SYM_DATA_END(wakeup_gdt)
.section ".rodata" ,"a"
.balign 8
/* This is the standard real-mode IDT */
.balign 16
SYM_DATA_START_LOCAL(.Lwakeup_idt)
.word 0 xffff /* limit */
.long 0 /* address */
.word 0
SYM_DATA_END(.Lwakeup_idt)
Messung V0.5 in Prozent C=99 H=92 G=95
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland