wakeup.S 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. .section ".jump", "ax"
  12. .globl _start
  13. _start:
  14. cli
  15. jmp wakeup_code
  16. /* This should match the structure in wakeup.h */
  17. .section ".header", "a"
  18. .globl wakeup_header
  19. wakeup_header:
  20. video_mode: .short 0 /* Video mode number */
  21. pmode_return: .byte 0x66, 0xea /* ljmpl */
  22. .long 0 /* offset goes here */
  23. .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. trampoline_segment: .word 0
  34. _pad1: .byte 0
  35. wakeup_jmp: .byte 0xea /* ljmpw */
  36. wakeup_jmp_off: .word 3f
  37. wakeup_jmp_seg: .word 0
  38. wakeup_gdt: .quad 0, 0, 0
  39. signature: .long WAKEUP_HEADER_SIGNATURE
  40. .text
  41. .code16
  42. wakeup_code:
  43. cld
  44. /* Apparently some dimwit BIOS programmers don't know how to
  45. program a PM to RM transition, and we might end up here with
  46. junk in the data segment descriptor registers. The only way
  47. to repair that is to go into PM and fix it ourselves... */
  48. movw $16, %cx
  49. lgdtl %cs:wakeup_gdt
  50. movl %cr0, %eax
  51. orb $X86_CR0_PE, %al
  52. movl %eax, %cr0
  53. jmp 1f
  54. 1: ljmpw $8, $2f
  55. 2:
  56. movw %cx, %ds
  57. movw %cx, %es
  58. movw %cx, %ss
  59. movw %cx, %fs
  60. movw %cx, %gs
  61. andb $~X86_CR0_PE, %al
  62. movl %eax, %cr0
  63. jmp wakeup_jmp
  64. 3:
  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. movl $wakeup_stack_end, %esp
  72. /* Clear the EFLAGS */
  73. pushl $0
  74. popfl
  75. /* Check header signature... */
  76. movl signature, %eax
  77. cmpl $WAKEUP_HEADER_SIGNATURE, %eax
  78. jne bogus_real_magic
  79. /* Check we really have everything... */
  80. movl end_signature, %eax
  81. cmpl $WAKEUP_END_SIGNATURE, %eax
  82. jne bogus_real_magic
  83. /* Call the C code */
  84. calll main
  85. /* Restore MISC_ENABLE before entering protected mode, in case
  86. BIOS decided to clear XD_DISABLE during S3. */
  87. movl pmode_behavior, %eax
  88. btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
  89. jnc 1f
  90. movl pmode_misc_en, %eax
  91. movl pmode_misc_en + 4, %edx
  92. movl $MSR_IA32_MISC_ENABLE, %ecx
  93. wrmsr
  94. 1:
  95. /* Do any other stuff... */
  96. #ifndef CONFIG_64BIT
  97. /* This could also be done in C code... */
  98. movl pmode_cr3, %eax
  99. movl %eax, %cr3
  100. movl pmode_cr4, %ecx
  101. jecxz 1f
  102. movl %ecx, %cr4
  103. 1:
  104. movl pmode_efer, %eax
  105. movl pmode_efer + 4, %edx
  106. movl %eax, %ecx
  107. orl %edx, %ecx
  108. jz 1f
  109. movl $MSR_EFER, %ecx
  110. wrmsr
  111. 1:
  112. lgdtl pmode_gdt
  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. bogus_real_magic:
  124. 1:
  125. hlt
  126. jmp 1b
  127. .data
  128. .balign 8
  129. /* This is the standard real-mode IDT */
  130. wakeup_idt:
  131. .word 0xffff /* limit */
  132. .long 0 /* address */
  133. .word 0
  134. .globl HEAP, heap_end
  135. HEAP:
  136. .long wakeup_heap
  137. heap_end:
  138. .long wakeup_stack
  139. .bss
  140. wakeup_heap:
  141. .space 2048
  142. wakeup_stack:
  143. .space 2048
  144. wakeup_stack_end:
  145. .section ".signature","a"
  146. end_signature:
  147. .long WAKEUP_END_SIGNATURE