wakeup_asm.S 3.7 KB

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