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