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