wakeup.S 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. .code16
  10. .section ".header", "a"
  11. /* This should match the structure in wakeup.h */
  12. .globl wakeup_header
  13. wakeup_header:
  14. video_mode: .short 0 /* Video mode number */
  15. pmode_return: .byte 0x66, 0xea /* ljmpl */
  16. .long 0 /* offset goes here */
  17. .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. realmode_flags: .long 0
  24. real_magic: .long 0
  25. trampoline_segment: .word 0
  26. _pad1: .byte 0
  27. wakeup_jmp: .byte 0xea /* ljmpw */
  28. wakeup_jmp_off: .word 3f
  29. wakeup_jmp_seg: .word 0
  30. wakeup_gdt: .quad 0, 0, 0
  31. signature: .long 0x51ee1111
  32. .text
  33. .globl _start
  34. .code16
  35. wakeup_code:
  36. _start:
  37. cli
  38. cld
  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. jmp 1f
  49. 1: ljmpw $8, $2f
  50. 2:
  51. movw %cx, %ds
  52. movw %cx, %es
  53. movw %cx, %ss
  54. movw %cx, %fs
  55. movw %cx, %gs
  56. andb $~X86_CR0_PE, %al
  57. movl %eax, %cr0
  58. jmp wakeup_jmp
  59. 3:
  60. /* Set up segments */
  61. movw %cs, %ax
  62. movw %ax, %ds
  63. movw %ax, %es
  64. movw %ax, %ss
  65. lidtl wakeup_idt
  66. movl $wakeup_stack_end, %esp
  67. /* Clear the EFLAGS */
  68. pushl $0
  69. popfl
  70. /* Check header signature... */
  71. movl signature, %eax
  72. cmpl $0x51ee1111, %eax
  73. jne bogus_real_magic
  74. /* Check we really have everything... */
  75. movl end_signature, %eax
  76. cmpl $0x65a22c82, %eax
  77. jne bogus_real_magic
  78. /* Call the C code */
  79. calll main
  80. /* Do any other stuff... */
  81. #ifndef CONFIG_64BIT
  82. /* This could also be done in C code... */
  83. movl pmode_cr3, %eax
  84. movl %eax, %cr3
  85. movl pmode_cr4, %ecx
  86. jecxz 1f
  87. movl %ecx, %cr4
  88. 1:
  89. movl pmode_efer, %eax
  90. movl pmode_efer + 4, %edx
  91. movl %eax, %ecx
  92. orl %edx, %ecx
  93. jz 1f
  94. movl $0xc0000080, %ecx
  95. wrmsr
  96. 1:
  97. lgdtl pmode_gdt
  98. /* This really couldn't... */
  99. movl pmode_cr0, %eax
  100. movl %eax, %cr0
  101. jmp pmode_return
  102. #else
  103. pushw $0
  104. pushw trampoline_segment
  105. pushw $0
  106. lret
  107. #endif
  108. bogus_real_magic:
  109. 1:
  110. hlt
  111. jmp 1b
  112. .data
  113. .balign 8
  114. /* This is the standard real-mode IDT */
  115. wakeup_idt:
  116. .word 0xffff /* limit */
  117. .long 0 /* address */
  118. .word 0
  119. .globl HEAP, heap_end
  120. HEAP:
  121. .long wakeup_heap
  122. heap_end:
  123. .long wakeup_stack
  124. .bss
  125. wakeup_heap:
  126. .space 2048
  127. wakeup_stack:
  128. .space 2048
  129. wakeup_stack_end: