wakeup.S 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. realmode_flags: .long 0
  30. real_magic: .long 0
  31. trampoline_segment: .word 0
  32. _pad1: .byte 0
  33. wakeup_jmp: .byte 0xea /* ljmpw */
  34. wakeup_jmp_off: .word 3f
  35. wakeup_jmp_seg: .word 0
  36. wakeup_gdt: .quad 0, 0, 0
  37. signature: .long WAKEUP_HEADER_SIGNATURE
  38. .text
  39. .code16
  40. wakeup_code:
  41. cld
  42. /* Apparently some dimwit BIOS programmers don't know how to
  43. program a PM to RM transition, and we might end up here with
  44. junk in the data segment descriptor registers. The only way
  45. to repair that is to go into PM and fix it ourselves... */
  46. movw $16, %cx
  47. lgdtl %cs:wakeup_gdt
  48. movl %cr0, %eax
  49. orb $X86_CR0_PE, %al
  50. movl %eax, %cr0
  51. jmp 1f
  52. 1: ljmpw $8, $2f
  53. 2:
  54. movw %cx, %ds
  55. movw %cx, %es
  56. movw %cx, %ss
  57. movw %cx, %fs
  58. movw %cx, %gs
  59. andb $~X86_CR0_PE, %al
  60. movl %eax, %cr0
  61. jmp wakeup_jmp
  62. 3:
  63. /* Set up segments */
  64. movw %cs, %ax
  65. movw %ax, %ds
  66. movw %ax, %es
  67. movw %ax, %ss
  68. lidtl wakeup_idt
  69. movl $wakeup_stack_end, %esp
  70. /* Clear the EFLAGS */
  71. pushl $0
  72. popfl
  73. /* Check header signature... */
  74. movl signature, %eax
  75. cmpl $WAKEUP_HEADER_SIGNATURE, %eax
  76. jne bogus_real_magic
  77. /* Check we really have everything... */
  78. movl end_signature, %eax
  79. cmpl $WAKEUP_END_SIGNATURE, %eax
  80. jne bogus_real_magic
  81. /* Call the C code */
  82. calll main
  83. /* Do any other stuff... */
  84. #ifndef CONFIG_64BIT
  85. /* This could also be done in C code... */
  86. movl pmode_cr3, %eax
  87. movl %eax, %cr3
  88. movl pmode_cr4, %ecx
  89. jecxz 1f
  90. movl %ecx, %cr4
  91. 1:
  92. movl pmode_efer, %eax
  93. movl pmode_efer + 4, %edx
  94. movl %eax, %ecx
  95. orl %edx, %ecx
  96. jz 1f
  97. movl $MSR_EFER, %ecx
  98. wrmsr
  99. 1:
  100. lgdtl pmode_gdt
  101. /* This really couldn't... */
  102. movl pmode_cr0, %eax
  103. movl %eax, %cr0
  104. jmp pmode_return
  105. #else
  106. pushw $0
  107. pushw trampoline_segment
  108. pushw $0
  109. lret
  110. #endif
  111. bogus_real_magic:
  112. 1:
  113. hlt
  114. jmp 1b
  115. .data
  116. .balign 8
  117. /* This is the standard real-mode IDT */
  118. wakeup_idt:
  119. .word 0xffff /* limit */
  120. .long 0 /* address */
  121. .word 0
  122. .globl HEAP, heap_end
  123. HEAP:
  124. .long wakeup_heap
  125. heap_end:
  126. .long wakeup_stack
  127. .bss
  128. wakeup_heap:
  129. .space 2048
  130. wakeup_stack:
  131. .space 2048
  132. wakeup_stack_end:
  133. .section ".signature","a"
  134. end_signature:
  135. .long WAKEUP_END_SIGNATURE