1/* 2 * linux/boot/head.S 3 * 4 * Copyright (C) 1991, 1992, 1993 Linus Torvalds 5 */ 6 7/* 8 * head.S contains the 32-bit startup code. 9 * 10 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where 11 * the page directory will exist. The startup code will be overwritten by 12 * the page directory. [According to comments etc elsewhere on a compressed 13 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] 14 * 15 * Page 0 is deliberately kept safe, since System Management Mode code in 16 * laptops may need to access the BIOS data stored there. This is also 17 * useful for future device drivers that either access the BIOS via VM86 18 * mode. 19 */ 20 21/* 22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 23 */ 24.code32 25.text 26 27#include <linux/linkage.h> 28#include <asm/segment.h> 29#include <asm/pgtable.h> 30#include <asm/page.h> 31#include <asm/boot.h> 32#include <asm/msr.h> 33#include <asm/processor-flags.h> 34#include <asm/asm-offsets.h> 35 36.section ".text.head" 37 .code32 38 .globl startup_32 39 40startup_32: 41 cld 42 /* test KEEP_SEGMENTS flag to see if the bootloader is asking 43 * us to not reload segments */ 44 testb $(1<<6), BP_loadflags(%esi) 45 jnz 1f 46 47 cli 48 movl $(__KERNEL_DS), %eax 49 movl %eax, %ds 50 movl %eax, %es 51 movl %eax, %ss 521: 53 54/* Calculate the delta between where we were compiled to run 55 * at and where we were actually loaded at. This can only be done 56 * with a short local call on x86. Nothing else will tell us what 57 * address we are running at. The reserved chunk of the real-mode 58 * data at 0x1e4 (defined as a scratch field) are used as the stack 59 * for this calculation. Only 4 bytes are needed. 60 */ 61 leal (0x1e4+4)(%esi), %esp 62 call 1f 631: popl %ebp 64 subl $1b, %ebp 65 66/* setup a stack and make sure cpu supports long mode. */ 67 movl $boot_stack_end, %eax 68 addl %ebp, %eax 69 movl %eax, %esp 70 71 call verify_cpu 72 testl %eax, %eax 73 jnz no_longmode 74 75/* Compute the delta between where we were compiled to run at 76 * and where the code will actually run at. 77 */ 78/* %ebp contains the address we are loaded at by the boot loader and %ebx 79 * contains the address where we should move the kernel image temporarily 80 * for safe in-place decompression. 81 */ 82 83#ifdef CONFIG_RELOCATABLE 84 movl %ebp, %ebx 85 addl $(PMD_PAGE_SIZE -1), %ebx 86 andl $PMD_PAGE_MASK, %ebx 87#else 88 movl $CONFIG_PHYSICAL_START, %ebx 89#endif 90 91 /* Replace the compressed data size with the uncompressed size */ 92 subl input_len(%ebp), %ebx 93 movl output_len(%ebp), %eax 94 addl %eax, %ebx 95 /* Add 8 bytes for every 32K input block */ 96 shrl $12, %eax 97 addl %eax, %ebx 98 /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ 99 addl $(32768 + 18 + 4095), %ebx 100 andl $~4095, %ebx 101 102/* 103 * Prepare for entering 64 bit mode 104 */ 105 106 /* Load new GDT with the 64bit segments using 32bit descriptor */ 107 leal gdt(%ebp), %eax 108 movl %eax, gdt+2(%ebp) 109 lgdt gdt(%ebp) 110 111 /* Enable PAE mode */ 112 xorl %eax, %eax 113 orl $(X86_CR4_PAE), %eax 114 movl %eax, %cr4 115 116 /* 117 * Build early 4G boot pagetable 118 */ 119 /* Initialize Page tables to 0*/ 120 leal pgtable(%ebx), %edi 121 xorl %eax, %eax 122 movl $((4096*6)/4), %ecx 123 rep stosl 124 125 /* Build Level 4 */ 126 leal pgtable + 0(%ebx), %edi 127 leal 0x1007 (%edi), %eax 128 movl %eax, 0(%edi) 129 130 /* Build Level 3 */ 131 leal pgtable + 0x1000(%ebx), %edi 132 leal 0x1007(%edi), %eax 133 movl $4, %ecx 1341: movl %eax, 0x00(%edi) 135 addl $0x00001000, %eax 136 addl $8, %edi 137 decl %ecx 138 jnz 1b 139 140 /* Build Level 2 */ 141 leal pgtable + 0x2000(%ebx), %edi 142 movl $0x00000183, %eax 143 movl $2048, %ecx 1441: movl %eax, 0(%edi) 145 addl $0x00200000, %eax 146 addl $8, %edi 147 decl %ecx 148 jnz 1b 149 150 /* Enable the boot page tables */ 151 leal pgtable(%ebx), %eax 152 movl %eax, %cr3 153 154 /* Enable Long mode in EFER (Extended Feature Enable Register) */ 155 movl $MSR_EFER, %ecx 156 rdmsr 157 btsl $_EFER_LME, %eax 158 wrmsr 159 160 /* Setup for the jump to 64bit mode 161 * 162 * When the jump is performend we will be in long mode but 163 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 164 * (and in turn EFER.LMA = 1). To jump into 64bit mode we use 165 * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 166 * We place all of the values on our mini stack so lret can 167 * used to perform that far jump. 168 */ 169 pushl $__KERNEL_CS 170 leal startup_64(%ebp), %eax 171 pushl %eax 172 173 /* Enter paged protected Mode, activating Long Mode */ 174 movl $(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */ 175 movl %eax, %cr0 176 177 /* Jump from 32bit compatibility mode into 64bit mode. */ 178 lret 179 180no_longmode: 181 /* This isn't an x86-64 CPU so hang */ 1821: 183 hlt 184 jmp 1b 185 186#include "../../kernel/verify_cpu_64.S" 187 188 /* Be careful here startup_64 needs to be at a predictable 189 * address so I can export it in an ELF header. Bootloaders 190 * should look at the ELF header to find this address, as 191 * it may change in the future. 192 */ 193 .code64 194 .org 0x200 195ENTRY(startup_64) 196 /* We come here either from startup_32 or directly from a 197 * 64bit bootloader. If we come here from a bootloader we depend on 198 * an identity mapped page table being provied that maps our 199 * entire text+data+bss and hopefully all of memory. 200 */ 201 202 /* Setup data segments. */ 203 xorl %eax, %eax 204 movl %eax, %ds 205 movl %eax, %es 206 movl %eax, %ss 207 movl %eax, %fs 208 movl %eax, %gs 209 lldt %ax 210 movl $0x20, %eax 211 ltr %ax 212 213 /* Compute the decompressed kernel start address. It is where 214 * we were loaded at aligned to a 2M boundary. %rbp contains the 215 * decompressed kernel start address. 216 * 217 * If it is a relocatable kernel then decompress and run the kernel 218 * from load address aligned to 2MB addr, otherwise decompress and 219 * run the kernel from CONFIG_PHYSICAL_START 220 */ 221 222 /* Start with the delta to where the kernel will run at. */ 223#ifdef CONFIG_RELOCATABLE 224 leaq startup_32(%rip) /* - $startup_32 */, %rbp 225 addq $(PMD_PAGE_SIZE - 1), %rbp 226 andq $PMD_PAGE_MASK, %rbp 227 movq %rbp, %rbx 228#else 229 movq $CONFIG_PHYSICAL_START, %rbp 230 movq %rbp, %rbx 231#endif 232 233 /* Replace the compressed data size with the uncompressed size */ 234 movl input_len(%rip), %eax 235 subq %rax, %rbx 236 movl output_len(%rip), %eax 237 addq %rax, %rbx 238 /* Add 8 bytes for every 32K input block */ 239 shrq $12, %rax 240 addq %rax, %rbx 241 /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ 242 addq $(32768 + 18 + 4095), %rbx 243 andq $~4095, %rbx 244 245/* Copy the compressed kernel to the end of our buffer 246 * where decompression in place becomes safe. 247 */ 248 leaq _end_before_pgt(%rip), %r8 249 leaq _end_before_pgt(%rbx), %r9 250 movq $_end_before_pgt /* - $startup_32 */, %rcx 2511: subq $8, %r8 252 subq $8, %r9 253 movq 0(%r8), %rax 254 movq %rax, 0(%r9) 255 subq $8, %rcx 256 jnz 1b 257 258/* 259 * Jump to the relocated address. 260 */ 261 leaq relocated(%rbx), %rax 262 jmp *%rax 263 264.section ".text" 265relocated: 266 267/* 268 * Clear BSS 269 */ 270 xorq %rax, %rax 271 leaq _edata(%rbx), %rdi 272 leaq _end_before_pgt(%rbx), %rcx 273 subq %rdi, %rcx 274 cld 275 rep 276 stosb 277 278 /* Setup the stack */ 279 leaq boot_stack_end(%rip), %rsp 280 281 /* zero EFLAGS after setting rsp */ 282 pushq $0 283 popfq 284 285/* 286 * Do the decompression, and jump to the new kernel.. 287 */ 288 pushq %rsi # Save the real mode argument 289 movq %rsi, %rdi # real mode address 290 leaq boot_heap(%rip), %rsi # malloc area for uncompression 291 leaq input_data(%rip), %rdx # input_data 292 movl input_len(%rip), %eax 293 movq %rax, %rcx # input_len 294 movq %rbp, %r8 # output 295 call decompress_kernel 296 popq %rsi 297 298 299/* 300 * Jump to the decompressed kernel. 301 */ 302 jmp *%rbp 303 304 .data 305gdt: 306 .word gdt_end - gdt 307 .long gdt 308 .word 0 309 .quad 0x0000000000000000 /* NULL descriptor */ 310 .quad 0x00af9a000000ffff /* __KERNEL_CS */ 311 .quad 0x00cf92000000ffff /* __KERNEL_DS */ 312 .quad 0x0080890000000000 /* TS descriptor */ 313 .quad 0x0000000000000000 /* TS continued */ 314gdt_end: 315 316.bss 317/* Stack and heap for uncompression */ 318.balign 4 319boot_heap: 320 .fill BOOT_HEAP_SIZE, 1, 0 321boot_stack: 322 .fill BOOT_STACK_SIZE, 1, 0 323boot_stack_end: 324