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