1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #if defined(__lint) 29 30 int fb_swtch_silence_lint = 0; 31 32 #else 33 34 #include <sys/asm_linkage.h> 35 #include <sys/segments.h> 36 #include <sys/controlregs.h> 37 #include <sys/machparam.h> 38 #include <sys/multiboot.h> 39 #include <sys/fastboot.h> 40 #include "assym.h" 41 42 /* 43 * This code is to switch from 64-bit or 32-bit to protected mode. 44 */ 45 46 /* 47 * For debugging with LEDs 48 */ 49 #define FB_OUTB_ASM(val) \ 50 movb val, %al; \ 51 outb $0x80; 52 53 54 #define DISABLE_PAGING \ 55 movl %cr0, %eax ;\ 56 btrl $31, %eax /* clear PG bit */ ;\ 57 movl %eax, %cr0 58 59 /* 60 * This macro contains common code for 64/32-bit versions of copy_sections(). 61 * On entry: 62 * fbf points to the fboot_file_t 63 * snum contains the number of sections 64 * Registers that would be clobbered: 65 * fbs, snum, %eax, %ecx, %edi, %esi. 66 * NOTE: fb_dest_pa is supposed to be in the first 1GB, 67 * therefore it is safe to use 32-bit register to hold it's value 68 * even for 64-bit code. 69 */ 70 71 #define COPY_SECT(fbf, fbs, snum) \ 72 lea FB_SECTIONS(fbf), fbs; \ 73 xorl %eax, %eax; \ 74 1: movl FB_DEST_PA(fbf), %esi; \ 75 addl FB_SEC_OFFSET(fbs), %esi; \ 76 movl FB_SEC_PADDR(fbs), %edi; \ 77 movl FB_SEC_SIZE(fbs), %ecx; \ 78 rep \ 79 movsb; \ 80 /* Zero BSS */ \ 81 movl FB_SEC_BSS_SIZE(fbs), %ecx; \ 82 rep \ 83 stosb; \ 84 add $FB_SECTIONS_INCR, fbs; \ 85 dec snum; \ 86 jnz 1b 87 88 89 .globl _start 90 _start: 91 92 /* Disable interrupts */ 93 cli 94 95 #if defined(__amd64) 96 /* Switch to a low memory stack */ 97 movq $_start, %rsp 98 addq $FASTBOOT_STACK_OFFSET, %rsp 99 100 /* 101 * Copy from old stack to new stack 102 * If the content before fi_valid gets bigger than 0x200 bytes, 103 * the reserved stack size above will need to be changed. 104 */ 105 movq %rdi, %rsi /* source from old stack */ 106 movq %rsp, %rdi /* destination on the new stack */ 107 movq $FI_VALID, %rcx /* size to copy */ 108 rep 109 smovb 110 111 #elif defined(__i386) 112 movl 0x4(%esp), %esi /* address of fastboot info struct */ 113 114 /* Switch to a low memory stack */ 115 movl $_start, %esp 116 addl $FASTBOOT_STACK_OFFSET, %esp 117 118 /* Copy struct to stack */ 119 movl %esp, %edi /* destination on the new stack */ 120 movl $FI_VALID, %ecx /* size to copy */ 121 rep 122 smovb 123 124 #endif 125 126 #if defined(__amd64) 127 128 xorl %eax, %eax 129 xorl %edx, %edx 130 131 movl $MSR_AMD_FSBASE, %ecx 132 wrmsr 133 134 movl $MSR_AMD_GSBASE, %ecx 135 wrmsr 136 137 movl $MSR_AMD_KGSBASE, %ecx 138 wrmsr 139 140 #endif 141 /* 142 * zero out all the registers to make sure they're 16 bit clean 143 */ 144 #if defined(__amd64) 145 xorq %r8, %r8 146 xorq %r9, %r9 147 xorq %r10, %r10 148 xorq %r11, %r11 149 xorq %r12, %r12 150 xorq %r13, %r13 151 xorq %r14, %r14 152 xorq %r15, %r15 153 #endif 154 xorl %eax, %eax 155 xorl %ebx, %ebx 156 xorl %ecx, %ecx 157 xorl %edx, %edx 158 xorl %ebp, %ebp 159 160 #if defined(__amd64) 161 /* 162 * Load our own GDT 163 */ 164 lgdt gdt_info 165 #endif 166 /* 167 * Load our own IDT 168 */ 169 lidt idt_info 170 171 #if defined(__amd64) 172 /* 173 * Invalidate all TLB entries. 174 * Load temporary pagetables to copy kernel and boot-archive 175 */ 176 movq %cr4, %rax 177 andq $_BITNOT(CR4_PGE), %rax 178 movq %rax, %cr4 179 movq FI_PAGETABLE_PA(%rsp), %rax 180 movq %rax, %cr3 181 182 leaq FI_FILES(%rsp), %rbx /* offset to the files */ 183 184 /* copy unix to final destination */ 185 movq FI_LAST_TABLE_PA(%rsp), %rsi /* page table PA */ 186 leaq _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi 187 call map_copy 188 189 /* copy boot archive to final destination */ 190 movq FI_LAST_TABLE_PA(%rsp), %rsi /* page table PA */ 191 leaq _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%rbx), %rdi 192 call map_copy 193 194 /* Copy sections if there are any */ 195 leaq _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi 196 movl FB_SECTCNT(%rdi), %esi 197 cmpl $0, %esi 198 je 1f 199 call copy_sections 200 1: 201 /* 202 * Shut down 64 bit mode. First get into compatiblity mode. 203 */ 204 movq %rsp, %rax 205 pushq $B32DATA_SEL 206 pushq %rax 207 pushf 208 pushq $B32CODE_SEL 209 pushq $1f 210 iretq 211 212 .code32 213 1: 214 movl $B32DATA_SEL, %eax 215 movw %ax, %ss 216 movw %ax, %ds 217 movw %ax, %es 218 movw %ax, %fs 219 movw %ax, %gs 220 221 /* 222 * Disable long mode by: 223 * - shutting down paging (bit 31 of cr0). This will flush the 224 * TLBs. 225 * - disabling LME (long mode enable) in EFER (extended feature reg) 226 */ 227 #endif 228 DISABLE_PAGING /* clobbers %eax */ 229 230 #if defined(__amd64) 231 ljmp $B32CODE_SEL, $1f 232 1: 233 #endif 234 235 /* 236 * Clear PGE, PAE and PSE flags as dboot expects them to be 237 * cleared. 238 */ 239 movl %cr4, %eax 240 andl $_BITNOT(CR4_PGE | CR4_PAE | CR4_PSE), %eax 241 movl %eax, %cr4 242 243 #if defined(__amd64) 244 movl $MSR_AMD_EFER, %ecx /* Extended Feature Enable */ 245 rdmsr 246 btcl $8, %eax /* bit 8 Long Mode Enable bit */ 247 wrmsr 248 249 #elif defined(__i386) 250 /* 251 * If fi_has_pae is set, re-enable paging with PAE. 252 */ 253 leal FI_FILES(%esp), %ebx /* offset to the files */ 254 movl FI_HAS_PAE(%esp), %edi /* need to enable paging or not */ 255 cmpl $0, %edi 256 je paging_on /* no need to enable paging */ 257 258 movl FI_LAST_TABLE_PA(%esp), %esi /* page table PA */ 259 260 /* 261 * Turn on PAE 262 */ 263 movl %cr4, %eax 264 orl $CR4_PAE, %eax 265 movl %eax, %cr4 266 267 /* 268 * Load top pagetable base address into cr3 269 */ 270 movl FI_PAGETABLE_PA(%esp), %eax 271 movl %eax, %cr3 272 273 movl %cr0, %eax 274 orl $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax 275 andl $_BITNOT(CR0_NW | CR0_CD), %eax 276 movl %eax, %cr0 277 jmp paging_on 278 paging_on: 279 280 /* copy unix to final destination */ 281 leal _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx 282 call map_copy 283 284 /* copy boot archive to final destination */ 285 leal _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%ebx), %edx 286 call map_copy 287 288 /* Disable paging one more time */ 289 DISABLE_PAGING 290 291 /* Copy sections if there are any */ 292 leal _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx 293 movl FB_SECTCNT(%edx), %eax 294 cmpl $0, %eax 295 je 1f 296 call copy_sections 297 1: 298 299 /* Whatever flags we turn on we need to turn off */ 300 movl %cr4, %eax 301 andl $_BITNOT(CR4_PAE), %eax 302 movl %eax, %cr4 303 #endif /* __i386 */ 304 305 dboot_jump: 306 /* Jump to dboot */ 307 movl $DBOOT_ENTRY_ADDRESS, %edi 308 movl FI_NEW_MBI_PA(%esp), %ebx 309 movl $MB_BOOTLOADER_MAGIC, %eax 310 jmp *%edi 311 312 #if defined(__amd64) 313 314 .code64 315 ENTRY_NP(copy_sections) 316 /* 317 * On entry 318 * %rdi points to the fboot_file_t 319 * %rsi contains number of sections 320 */ 321 movq %rdi, %rdx 322 movq %rsi, %r9 323 324 COPY_SECT(%rdx, %r8, %r9) 325 ret 326 SET_SIZE(copy_sections) 327 328 ENTRY_NP(map_copy) 329 /* 330 * On entry 331 * %rdi points to the fboot_file_t 332 * %rsi has FI_LAST_TABLE_PA(%rsp) 333 */ 334 335 movq %rdi, %rdx 336 movq %rsi, %r8 337 movq FB_PTE_LIST_PA(%rdx), %rax /* PA list of the source */ 338 movq FB_DEST_PA(%rdx), %rdi /* PA of the destination */ 339 340 2: 341 movq (%rax), %rcx /* Are we done? */ 342 cmpl $FASTBOOT_TERMINATE, %ecx 343 je 1f 344 345 movq %rcx, (%r8) 346 movq %cr3, %rsi /* Reload cr3 */ 347 movq %rsi, %cr3 348 movq FB_VA(%rdx), %rsi /* Load from VA */ 349 movq $PAGESIZE, %rcx 350 shrq $3, %rcx /* 8-byte at a time */ 351 rep 352 smovq 353 addq $8, %rax /* Go to next PTE */ 354 jmp 2b 355 1: 356 ret 357 SET_SIZE(map_copy) 358 359 #elif defined(__i386) 360 361 ENTRY_NP(copy_sections) 362 /* 363 * On entry 364 * %edx points to the fboot_file_t 365 * %eax contains the number of sections 366 */ 367 pushl %ebp 368 pushl %ebx 369 pushl %esi 370 pushl %edi 371 372 movl %eax, %ebp 373 374 COPY_SECT(%edx, %ebx, %ebp) 375 376 popl %edi 377 popl %esi 378 popl %ebx 379 popl %ebp 380 ret 381 SET_SIZE(copy_sections) 382 383 ENTRY_NP(map_copy) 384 /* 385 * On entry 386 * %edx points to the fboot_file_t 387 * %edi has FB_HAS_PAE(%esp) 388 * %esi has FI_LAST_TABLE_PA(%esp) 389 */ 390 pushl %eax 391 pushl %ebx 392 pushl %ecx 393 pushl %edx 394 pushl %ebp 395 pushl %esi 396 pushl %edi 397 movl %esi, %ebp /* Save page table PA in %ebp */ 398 399 movl FB_PTE_LIST_PA(%edx), %eax /* PA list of the source */ 400 movl FB_DEST_PA(%edx), %ebx /* PA of the destination */ 401 402 loop: 403 movl (%eax), %esi /* Are we done? */ 404 cmpl $FASTBOOT_TERMINATE, %esi 405 je done 406 407 cmpl $1, (%esp) /* Is paging on? */ 408 jne no_paging /* Nope */ 409 410 movl %ebp, %edi /* Page table PA */ 411 movl %esi, (%edi) /* Program low 32-bit */ 412 movl 4(%eax), %esi /* high bits of the table */ 413 movl %esi, 4(%edi) /* Program high 32-bit */ 414 movl %cr3, %esi /* Reload cr3 */ 415 movl %esi, %cr3 416 movl FB_VA(%edx), %esi /* Load from VA */ 417 jmp do_copy 418 no_paging: 419 andl $_BITNOT(MMU_PAGEOFFSET), %esi /* clear lower 12-bit */ 420 do_copy: 421 movl %ebx, %edi 422 movl $PAGESIZE, %ecx 423 shrl $2, %ecx /* 4-byte at a time */ 424 rep 425 smovl 426 addl $8, %eax /* We built the PTEs as 8-byte entries */ 427 addl $PAGESIZE, %ebx 428 jmp loop 429 done: 430 popl %edi 431 popl %esi 432 popl %ebp 433 popl %edx 434 popl %ecx 435 popl %ebx 436 popl %eax 437 ret 438 SET_SIZE(map_copy) 439 #endif /* __i386 */ 440 441 442 idt_info: 443 .value 0x3ff 444 .quad 0 445 446 /* 447 * We need to trampoline thru a gdt we have in low memory. 448 */ 449 #include "../boot/boot_gdt.s" 450 #endif /* __lint */