mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-23 19:14:30 +08:00
4aec216b93
All these are functions which are invoked from elsewhere but they are not typical C functions. So annotate them using the new SYM_CODE_START. All these were not balanced with any END, so mark their ends by SYM_CODE_END appropriately too. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> [xen bits] Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> [power mgmt] Cc: Andy Shevchenko <andy@infradead.org> Cc: Cao jin <caoj.fnst@cn.fujitsu.com> Cc: Darren Hart <dvhart@infradead.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: linux-arch@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: Pavel Machek <pavel@ucw.cz> Cc: Pingfan Liu <kernelfans@gmail.com> Cc: platform-driver-x86@vger.kernel.org Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Wei Huang <wei@redhat.com> Cc: x86-ml <x86@kernel.org> Cc: xen-devel@lists.xenproject.org Cc: Xiaoyao Li <xiaoyao.li@linux.intel.com> Link: https://lkml.kernel.org/r/20191011115108.12392-23-jslaby@suse.cz
180 lines
3.8 KiB
ArmAsm
180 lines
3.8 KiB
ArmAsm
/* 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_behavior: .long 0 /* Wakeup behavior flags */
|
|
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(3f)
|
|
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, $2f
|
|
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(3f)
|
|
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 1f
|
|
|
|
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 1f
|
|
movl pmode_cr4, %eax
|
|
movl %eax, %cr4
|
|
1:
|
|
btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
|
|
jnc 1f
|
|
movl pmode_efer, %eax
|
|
movl pmode_efer + 4, %edx
|
|
movl $MSR_EFER, %ecx
|
|
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 1b
|
|
|
|
.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(wakeup_gdt)
|
|
.word 3*8-1 /* Self-descriptor */
|
|
.long pa_wakeup_gdt
|
|
.word 0
|
|
|
|
.word 0xffff /* 16-bit code segment @ real_mode_base */
|
|
.long 0x9b000000 + pa_real_mode_base
|
|
.word 0x008f /* big real mode */
|
|
|
|
.word 0xffff /* 16-bit data segment @ real_mode_base */
|
|
.long 0x93000000 + pa_real_mode_base
|
|
.word 0x008f /* 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 0xffff /* limit */
|
|
.long 0 /* address */
|
|
.word 0
|
|
SYM_DATA_END(.Lwakeup_idt)
|