1/* 2 * Trampoline code relocated to low memory. 3 * 4 * Care must taken when referencing symbols: they live in the relocated 5 * trampoline and in the hypervisor binary. The hypervisor symbols can either 6 * be accessed by their virtual address or by the physical address. When 7 * using the physical address eventually the physical start address of the 8 * hypervisor must be taken into account: after early boot the hypervisor 9 * will copy itself to high memory and writes its physical start address to 10 * trampoline_xen_phys_start in the low memory trampoline copy. 11 * 12 * Parts of the trampoline are needed for early boot only, while some other 13 * parts are needed as long as the hypervisor is active (e.g. wakeup code 14 * after suspend, bringup code for secondary cpus). The permanent parts should 15 * not reference any temporary low memory trampoline parts as those parts are 16 * not guaranteed to persist. 17 */ 18 19/* NB. bootsym() is only usable in real mode, or via BOOT_PSEUDORM_DS. */ 20#undef bootsym 21#define bootsym(s) ((s)-trampoline_start) 22 23#define bootsym_rel(sym, off, opnd...) \ 24 bootsym(sym),##opnd; \ 25111:; \ 26 .pushsection .trampoline_rel, "a"; \ 27 .long 111b - (off) - .; \ 28 .popsection 29 30#define bootsym_segrel(sym, off) \ 31 $0,$bootsym(sym); \ 32111:; \ 33 .pushsection .trampoline_seg, "a"; \ 34 .long 111b - (off) - .; \ 35 .popsection 36 37/* Start of the permanent trampoline code. */ 38 39 .code16 40 41GLOBAL(trampoline_realmode_entry) 42 mov %cs,%ax 43 mov %ax,%ds 44 movb $0xA5,bootsym(trampoline_cpu_started) 45 cld 46 cli 47 lidt bootsym(idt_48) 48 lgdt bootsym(gdt_48) 49 mov $1,%bl # EBX != 0 indicates we are an AP 50 xor %ax, %ax 51 inc %ax 52 lmsw %ax # CR0.PE = 1 (enter protected mode) 53 ljmpl $BOOT_CS32,$bootsym_rel(trampoline_protmode_entry,6) 54 55 .balign 8 56 .word 0 57idt_48: .word 0, 0, 0 # base = limit = 0 58 .word 0 59gdt_48: .word 6*8-1 60 .long bootsym_rel(trampoline_gdt,4) 61 62trampoline_gdt: 63 /* 0x0000: unused */ 64 .quad 0x0000000000000000 65 /* 0x0008: ring 0 code, 32-bit mode */ 66 .quad 0x00cf9a000000ffff 67 /* 0x0010: ring 0 code, 64-bit mode */ 68 .quad 0x00af9a000000ffff 69 /* 0x0018: ring 0 data */ 70 .quad 0x00cf92000000ffff 71 /* 0x0020: real-mode code @ BOOT_TRAMPOLINE */ 72 .long 0x0000ffff 73 .long 0x00009a00 74 /* 0x0028: real-mode data @ BOOT_TRAMPOLINE */ 75 .long 0x0000ffff 76 .long 0x00009200 77 /* 78 * 0x0030: ring 0 Xen data, 16 MiB size, base 79 * address is computed at runtime. 80 */ 81 .quad 0x00c0920000000fff 82 83 .pushsection .trampoline_rel, "a" 84 .long trampoline_gdt + BOOT_PSEUDORM_CS + 2 - . 85 .long trampoline_gdt + BOOT_PSEUDORM_DS + 2 - . 86 .popsection 87 88GLOBAL(trampoline_misc_enable_off) 89 .quad 0 90 91GLOBAL(cpuid_ext_features) 92 .long 0 93 94GLOBAL(trampoline_xen_phys_start) 95 .long 0 96 97GLOBAL(trampoline_cpu_started) 98 .byte 0 99 100 .code32 101trampoline_protmode_entry: 102 /* Set up a few descriptors: on entry only CS is guaranteed good. */ 103 mov $BOOT_DS,%eax 104 mov %eax,%ds 105 mov %eax,%es 106 107 /* Set up FPU. */ 108 fninit 109 110 /* Initialise CR4. */ 111 mov $X86_CR4_PAE,%ecx 112 mov %ecx,%cr4 113 114 /* Load pagetable base register. */ 115 mov $sym_offs(idle_pg_table),%eax 116 add bootsym_rel(trampoline_xen_phys_start,4,%eax) 117 mov %eax,%cr3 118 119 /* Adjust IA32_MISC_ENABLE if needed (for NX enabling below). */ 120 mov bootsym_rel(trampoline_misc_enable_off,4,%esi) 121 mov bootsym_rel(trampoline_misc_enable_off+4,4,%edi) 122 mov %esi,%eax 123 or %edi,%eax 124 jz 1f 125 mov $MSR_IA32_MISC_ENABLE,%ecx 126 rdmsr 127 not %esi 128 not %edi 129 and %esi,%eax 130 and %edi,%edx 131 wrmsr 1321: 133 134 /* Set up EFER (Extended Feature Enable Register). */ 135 mov bootsym_rel(cpuid_ext_features,4,%edi) 136 movl $MSR_EFER,%ecx 137 rdmsr 138 or $EFER_LME|EFER_SCE,%eax /* Long Mode + SYSCALL/SYSRET */ 139 bt $cpufeat_bit(X86_FEATURE_NX),%edi /* No Execute? */ 140 jnc 1f 141 btsl $_EFER_NX,%eax /* No Execute */ 1421: wrmsr 143 144 mov $(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE |\ 145 X86_CR0_ET | X86_CR0_MP | X86_CR0_PE), %eax 146 mov %eax,%cr0 147 jmp 1f 1481: 149 150 /* Now in compatibility mode. Long-jump into 64-bit mode. */ 151 ljmp $BOOT_CS64,$bootsym_rel(start64,6) 152 153 .code64 154start64: 155 /* Jump to high mappings. */ 156 movabs $__high_start,%rax 157 jmpq *%rax 158 159#include "wakeup.S" 160 161/* The first page of trampoline is permanent, the rest boot-time only. */ 162/* Reuse the boot trampoline on the 1st trampoline page as stack for wakeup. */ 163 .equ wakeup_stack, trampoline_start + PAGE_SIZE 164 .global wakeup_stack 165 166/* From here on early boot only. */ 167 168 .code32 169trampoline_boot_cpu_entry: 170 cmpb $0,bootsym_rel(skip_realmode,5) 171 jnz .Lskip_realmode 172 173 /* Load pseudo-real-mode segments. */ 174 mov $BOOT_PSEUDORM_DS,%eax 175 mov %eax,%ds 176 mov %eax,%es 177 mov %eax,%fs 178 mov %eax,%gs 179 mov %eax,%ss 180 181 /* Switch to pseudo-rm CS, enter real mode, and flush insn queue. */ 182 mov %cr0,%eax 183 dec %eax 184 ljmp $BOOT_PSEUDORM_CS,$bootsym(1f) 185 .code16 1861: mov %eax,%cr0 # CR0.PE = 0 (leave protected mode) 187 188 /* Load proper real-mode values into %cs, %ds, %es and %ss. */ 189 ljmp bootsym_segrel(1f,2) 1901: mov %cs,%ax 191 mov %ax,%ds 192 mov %ax,%es 193 mov %ax,%ss 194 195 /* Initialise stack pointer and IDT, and enable irqs. */ 196 xor %esp,%esp 197 lidt bootsym(rm_idt) 198 sti 199 200 /* 201 * Declare that our target operating mode is long mode. 202 * Initialise 32-bit registers since some buggy BIOSes depend on it. 203 */ 204 xor %ecx,%ecx 205 xor %edx,%edx 206 xor %esi,%esi 207 xor %edi,%edi 208 xor %ebp,%ebp 209 movl $0xec00,%eax # declare target operating mode 210 movl $0x0002,%ebx # long mode 211 int $0x15 212 213 /* 214 * Do real-mode work: 215 * 1. Get memory map. 216 * 2. Get Enhanced Disk Drive (EDD) information. 217 * 3. Set video mode. 218 * 4. Get keyboard shift flags. 219 */ 220 call get_memory_map 221 call get_edd 222#ifdef CONFIG_VIDEO 223 call video 224#endif 225 226 mov $0x0200,%ax 227 int $0x16 228 mov %al,bootsym(kbd_shift_flags) 229 230 /* Disable irqs before returning to protected mode. */ 231 cli 232 233 /* Reset GDT and IDT. Some BIOSes clobber GDTR. */ 234 lidt bootsym(idt_48) 235 lgdt bootsym(gdt_48) 236 237 /* Enter protected mode, and flush insn queue. */ 238 xor %ax,%ax 239 inc %ax 240 lmsw %ax # CR0.PE = 1 (enter protected mode) 241 242 /* Load proper protected-mode values into all segment registers. */ 243 ljmpl $BOOT_CS32,$bootsym_rel(1f,6) 244 .code32 2451: mov $BOOT_DS,%eax 246 mov %eax,%ds 247 mov %eax,%es 248 mov %eax,%fs 249 mov %eax,%gs 250 mov %eax,%ss 251 252.Lskip_realmode: 253 /* EBX == 0 indicates we are the BP (Boot Processor). */ 254 xor %ebx,%ebx 255 256 /* Jump to the common bootstrap entry point. */ 257 jmp trampoline_protmode_entry 258 259#include "video.h" 260 261 .align 2 262/* Keep in sync with cmdline.c:early_boot_opts_t type! */ 263early_boot_opts: 264skip_realmode: 265 .byte 0 266opt_edd: 267 .byte 0 /* edd=on/off/skipmbr */ 268opt_edid: 269 .byte 0 /* EDID parsing option (force/no/default). */ 270/* Padding. */ 271 .byte 0 272 273#ifdef CONFIG_VIDEO 274GLOBAL(boot_vid_mode) 275 .word VIDEO_80x25 /* If we don't run at all, assume basic video mode 3 at 80x25. */ 276vesa_size: 277 .word 0,0,0 /* width x depth x height */ 278#endif 279 280GLOBAL(kbd_shift_flags) 281 .byte 0 282 283rm_idt: .word 256*4-1, 0, 0 284 285#include "mem.S" 286#include "edd.S" 287#ifdef CONFIG_VIDEO 288#include "video.S" 289#endif 290