linux/arch/x86/kernel/acpi/realmode/wakeup.S
<<
>>
Prefs
   1/*
   2 * ACPI wakeup real mode startup stub
   3 */
   4#include <asm/segment.h>
   5#include <asm/msr-index.h>
   6#include <asm/page_types.h>
   7#include <asm/pgtable_types.h>
   8#include <asm/processor-flags.h>
   9
  10        .code16
  11        .section ".header", "a"
  12
  13/* This should match the structure in wakeup.h */
  14                .globl  wakeup_header
  15wakeup_header:
  16video_mode:     .short  0       /* Video mode number */
  17pmode_return:   .byte   0x66, 0xea      /* ljmpl */
  18                .long   0       /* offset goes here */
  19                .short  __KERNEL_CS
  20pmode_cr0:      .long   0       /* Saved %cr0 */
  21pmode_cr3:      .long   0       /* Saved %cr3 */
  22pmode_cr4:      .long   0       /* Saved %cr4 */
  23pmode_efer:     .quad   0       /* Saved EFER */
  24pmode_gdt:      .quad   0
  25realmode_flags: .long   0
  26real_magic:     .long   0
  27trampoline_segment:     .word 0
  28_pad1:          .byte   0
  29wakeup_jmp:     .byte   0xea    /* ljmpw */
  30wakeup_jmp_off: .word   3f
  31wakeup_jmp_seg: .word   0
  32wakeup_gdt:     .quad   0, 0, 0
  33signature:      .long   0x51ee1111
  34
  35        .text
  36        .globl  _start
  37        .code16
  38wakeup_code:
  39_start:
  40        cli
  41        cld
  42
  43        /* Apparently some dimwit BIOS programmers don't know how to
  44           program a PM to RM transition, and we might end up here with
  45           junk in the data segment descriptor registers.  The only way
  46           to repair that is to go into PM and fix it ourselves... */
  47        movw    $16, %cx
  48        lgdtl   %cs:wakeup_gdt
  49        movl    %cr0, %eax
  50        orb     $X86_CR0_PE, %al
  51        movl    %eax, %cr0
  52        jmp     1f
  531:      ljmpw   $8, $2f
  542:
  55        movw    %cx, %ds
  56        movw    %cx, %es
  57        movw    %cx, %ss
  58        movw    %cx, %fs
  59        movw    %cx, %gs
  60
  61        andb    $~X86_CR0_PE, %al
  62        movl    %eax, %cr0
  63        jmp     wakeup_jmp
  643:
  65        /* Set up segments */
  66        movw    %cs, %ax
  67        movw    %ax, %ds
  68        movw    %ax, %es
  69        movw    %ax, %ss
  70        lidtl   wakeup_idt
  71
  72        movl    $wakeup_stack_end, %esp
  73
  74        /* Clear the EFLAGS */
  75        pushl   $0
  76        popfl
  77
  78        /* Check header signature... */
  79        movl    signature, %eax
  80        cmpl    $0x51ee1111, %eax
  81        jne     bogus_real_magic
  82
  83        /* Check we really have everything... */
  84        movl    end_signature, %eax
  85        cmpl    $0x65a22c82, %eax
  86        jne     bogus_real_magic
  87
  88        /* Call the C code */
  89        calll   main
  90
  91        /* Do any other stuff... */
  92
  93#ifndef CONFIG_64BIT
  94        /* This could also be done in C code... */
  95        movl    pmode_cr3, %eax
  96        movl    %eax, %cr3
  97
  98        movl    pmode_cr4, %ecx
  99        jecxz   1f
 100        movl    %ecx, %cr4
 1011:
 102        movl    pmode_efer, %eax
 103        movl    pmode_efer + 4, %edx
 104        movl    %eax, %ecx
 105        orl     %edx, %ecx
 106        jz      1f
 107        movl    $MSR_EFER, %ecx
 108        wrmsr
 1091:
 110
 111        lgdtl   pmode_gdt
 112
 113        /* This really couldn't... */
 114        movl    pmode_cr0, %eax
 115        movl    %eax, %cr0
 116        jmp     pmode_return
 117#else
 118        pushw   $0
 119        pushw   trampoline_segment
 120        pushw   $0
 121        lret
 122#endif
 123
 124bogus_real_magic:
 1251:
 126        hlt
 127        jmp     1b
 128
 129        .data
 130        .balign 8
 131
 132        /* This is the standard real-mode IDT */
 133wakeup_idt:
 134        .word   0xffff          /* limit */
 135        .long   0               /* address */
 136        .word   0
 137
 138        .globl  HEAP, heap_end
 139HEAP:
 140        .long   wakeup_heap
 141heap_end:
 142        .long   wakeup_stack
 143
 144        .bss
 145wakeup_heap:
 146        .space  2048
 147wakeup_stack:
 148        .space  2048
 149wakeup_stack_end:
 150