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 41/* 42 * do_boot_cpu() programs the Startup-IPI to point here. Due to the SIPI 43 * format, the relocated entrypoint must be 4k aligned. 44 * 45 * It is entered in Real Mode, with %cs = trampoline_realmode_entry >> 4 and 46 * %ip = 0. 47 */ 48GLOBAL(trampoline_realmode_entry) 49 mov %cs,%ax 50 mov %ax,%ds 51 movb $0xA5,bootsym(trampoline_cpu_started) 52 cld 53 cli 54 lidt bootsym(idt_48) 55 lgdt bootsym(gdt_48) 56 mov $X86_CR0_PE, %ebx # EBX != 0 indicates we are an AP 57 mov %ebx, %cr0 # Alias with CR0.PE for brevity 58 59 ljmpl $BOOT_CS32,$bootsym_rel(trampoline_protmode_entry,6) 60 61 .code32 62trampoline_protmode_entry: 63 /* Set up a few descriptors: on entry only CS is guaranteed good. */ 64 mov $BOOT_DS,%eax 65 mov %eax,%ds 66 mov %eax,%es 67 68 /* Set up FPU. */ 69 fninit 70 71 /* Initialise CR4. */ 72 mov $X86_CR4_PAE,%ecx 73 mov %ecx,%cr4 74 75 /* Load pagetable base register. */ 76 mov $sym_offs(idle_pg_table),%eax 77 add bootsym_rel(trampoline_xen_phys_start,4,%eax) 78 mov %eax,%cr3 79 80 /* Adjust IA32_MISC_ENABLE if needed (for NX enabling below). */ 81 mov bootsym_rel(trampoline_misc_enable_off,4,%esi) 82 mov bootsym_rel(trampoline_misc_enable_off+4,4,%edi) 83 mov %esi,%eax 84 or %edi,%eax 85 jz 1f 86 mov $MSR_IA32_MISC_ENABLE,%ecx 87 rdmsr 88 not %esi 89 not %edi 90 and %esi,%eax 91 and %edi,%edx 92 wrmsr 931: 94 /* Set up PAT before enabling paging. */ 95 mov $XEN_MSR_PAT & 0xffffffff, %eax 96 mov $XEN_MSR_PAT >> 32, %edx 97 mov $MSR_IA32_CR_PAT, %ecx 98 wrmsr 99 100 /* Set up EFER (Extended Feature Enable Register). */ 101 movl $MSR_EFER,%ecx 102 rdmsr 103 or bootsym_rel(trampoline_efer, 4, %eax) 104 wrmsr 105 106 mov $(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE |\ 107 X86_CR0_ET | X86_CR0_MP | X86_CR0_PE), %eax 108 mov %eax,%cr0 109 110 /* Now in compatibility mode. Long-jump into 64-bit mode. */ 111 ljmp $BOOT_CS64,$bootsym_rel(start64,6) 112 113 .code64 114start64: 115 /* Jump to high mappings. */ 116 movabs $__high_start, %rdi 117 jmpq *%rdi 118 119#include "video.h" 120#include "wakeup.S" 121 122 .balign 8 123 .word 0 124idt_48: .word 0, 0, 0 # base = limit = 0 125 126trampoline_gdt: 127 .word 0 /* 0x0000: unused (reused for GDTR) */ 128gdt_48: 129 .word .Ltrampoline_gdt_end - trampoline_gdt - 1 130 .long bootsym_rel(trampoline_gdt, 4) 131 132 .quad 0x00cf9b000000ffff /* 0x0008: ring 0 code, 32-bit mode */ 133 .quad 0x00af9b000000ffff /* 0x0010: ring 0 code, 64-bit mode */ 134 .quad 0x00cf93000000ffff /* 0x0018: ring 0 data */ 135 .quad 0x00009b000000ffff /* 0x0020: real-mode code @ BOOT_TRAMPOLINE */ 136 .quad 0x000093000000ffff /* 0x0028: real-mode data @ BOOT_TRAMPOLINE */ 137.Ltrampoline_gdt_end: 138 139 /* Relocations for trampoline Real Mode segments. */ 140 .pushsection .trampoline_rel, "a" 141 .long trampoline_gdt + BOOT_PSEUDORM_CS + 2 - . 142 .long trampoline_gdt + BOOT_PSEUDORM_DS + 2 - . 143 .popsection 144 145GLOBAL(trampoline_misc_enable_off) 146 .quad 0 147 148/* EFER OR-mask for boot paths. SCE conditional on PV support, NX added when available. */ 149GLOBAL(trampoline_efer) 150 .long EFER_LME | (EFER_SCE * IS_ENABLED(CONFIG_PV)) 151 152GLOBAL(trampoline_xen_phys_start) 153 .long 0 154 155GLOBAL(trampoline_cpu_started) 156 .byte 0 157 158/* The first page of trampoline is permanent, the rest boot-time only. */ 159/* Reuse the boot trampoline on the 1st trampoline page as stack for wakeup. */ 160 .equ wakeup_stack, trampoline_start + PAGE_SIZE 161 .global wakeup_stack 162 163/* From here on early boot only. */ 164 165 .code32 166trampoline_boot_cpu_entry: 167 cmpb $0,bootsym_rel(skip_realmode,5) 168 jnz .Lskip_realmode 169 170 /* Load pseudo-real-mode segments. */ 171 mov $BOOT_PSEUDORM_DS,%eax 172 mov %eax,%ds 173 mov %eax,%es 174 mov %eax,%fs 175 mov %eax,%gs 176 mov %eax,%ss 177 178 /* Switch to pseudo-rm CS, enter real mode, and flush insn queue. */ 179 mov %cr0,%eax 180 dec %eax 181 ljmp $BOOT_PSEUDORM_CS,$bootsym(1f) 182 .code16 1831: mov %eax,%cr0 # CR0.PE = 0 (leave protected mode) 184 185 /* Load proper real-mode values into %cs, %ds, %es and %ss. */ 186 ljmp bootsym_segrel(1f,2) 1871: mov %cs,%ax 188 mov %ax,%ds 189 mov %ax,%es 190 mov %ax,%ss 191 192 /* Initialise stack pointer and IDT, and enable irqs. */ 193 xor %esp,%esp 194 lidt bootsym(rm_idt) 195 sti 196 197 /* 198 * Declare that our target operating mode is long mode. 199 * Initialise 32-bit registers since some buggy BIOSes depend on it. 200 */ 201 xor %ecx,%ecx 202 xor %edx,%edx 203 xor %esi,%esi 204 xor %edi,%edi 205 xor %ebp,%ebp 206 movl $0xec00,%eax # declare target operating mode 207 movl $0x0002,%ebx # long mode 208 int $0x15 209 210 /* 211 * Do real-mode work: 212 * 1. Get memory map. 213 * 2. Get Enhanced Disk Drive (EDD) information. 214 * 3. Set video mode. 215 * 4. Get keyboard shift flags. 216 */ 217 call get_memory_map 218 call get_edd 219#ifdef CONFIG_VIDEO 220 call video 221#endif 222 223 mov $0x0200,%ax 224 int $0x16 225 mov %al,bootsym(kbd_shift_flags) 226 227 /* Disable irqs before returning to protected mode. */ 228 cli 229 230 /* Reset GDT and IDT. Some BIOSes clobber GDTR. */ 231 lidt bootsym(idt_48) 232 lgdt bootsym(gdt_48) 233 234 /* Enter protected mode, and flush insn queue. */ 235 mov $X86_CR0_PE, %eax 236 mov %eax, %cr0 237 238 /* Load proper protected-mode values into all segment registers. */ 239 ljmpl $BOOT_CS32,$bootsym_rel(1f,6) 240 .code32 2411: mov $BOOT_DS,%eax 242 mov %eax,%ds 243 mov %eax,%es 244 mov %eax,%fs 245 mov %eax,%gs 246 mov %eax,%ss 247 248.Lskip_realmode: 249 /* EBX == 0 indicates we are the BP (Boot Processor). */ 250 xor %ebx,%ebx 251 252 /* Jump to the common bootstrap entry point. */ 253 jmp trampoline_protmode_entry 254 255 .align 2 256/* Keep in sync with cmdline.c:early_boot_opts_t type! */ 257early_boot_opts: 258skip_realmode: 259 .byte 0 260opt_edd: 261 .byte 0 /* edd=on/off/skipmbr */ 262opt_edid: 263 .byte 0 /* EDID parsing option (force/no/default). */ 264/* Padding. */ 265 .byte 0 266 267#ifdef CONFIG_VIDEO 268boot_vid_mode: 269 .word VIDEO_80x25 /* If we don't run at all, assume basic video mode 3 at 80x25. */ 270vesa_size: 271 .word 0,0,0 /* width x depth x height */ 272#endif 273 274GLOBAL(kbd_shift_flags) 275 .byte 0 276 277rm_idt: .word 256*4-1, 0, 0 278 279#include "mem.S" 280#include "edd.S" 281#ifdef CONFIG_VIDEO 282#include "video.S" 283#endif 284