1ae115bc7Smrj/* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj 22ae115bc7Smrj/* 23ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24ae115bc7Smrj * Use is subject to license terms. 25ae115bc7Smrj */ 26ae115bc7Smrj 279b0bb795SJohn Levon/* 289b0bb795SJohn Levon * Copyright 2019 Joyent, Inc. 299b0bb795SJohn Levon */ 30ae115bc7Smrj 31ae115bc7Smrj#include <sys/segments.h> 32ae115bc7Smrj#include <sys/controlregs.h> 33ae115bc7Smrj 34ae115bc7Smrj/* 35ae115bc7Smrj * Do a call into BIOS. This goes down to 16 bit real mode and back again. 36ae115bc7Smrj */ 37ae115bc7Smrj 38ae115bc7Smrj/* 39ae115bc7Smrj * instruction prefix to change operand size in instruction 40ae115bc7Smrj */ 41ae115bc7Smrj#define DATASZ .byte 0x66; 42ae115bc7Smrj 43ae115bc7Smrj .globl _start 44ae115bc7Smrj_start: 45ae115bc7Smrj 46ae115bc7Smrj /* 47ae115bc7Smrj * Save caller registers 48ae115bc7Smrj */ 49ae115bc7Smrj movq %rbp, save_rbp 50ae115bc7Smrj movq %rsp, save_rsp 51ae115bc7Smrj movq %rbx, save_rbx 52ae115bc7Smrj movq %rsi, save_rsi 53ae115bc7Smrj movq %r12, save_r12 54ae115bc7Smrj movq %r13, save_r13 55ae115bc7Smrj movq %r14, save_r14 56ae115bc7Smrj movq %r15, save_r15 57ae115bc7Smrj 58ae115bc7Smrj /* Switch to a low memory stack */ 59ae115bc7Smrj movq $_start, %rsp 60ae115bc7Smrj 61ae115bc7Smrj /* put interrupt number in %bl */ 62ae115bc7Smrj movq %rdi, %rbx 63ae115bc7Smrj 64ae115bc7Smrj /* allocate space for args on stack */ 65ae115bc7Smrj subq $18, %rsp 66ae115bc7Smrj movq %rsp, %rdi 67ae115bc7Smrj 68ae115bc7Smrj /* copy args from high memory to stack in low memory */ 69ae115bc7Smrj cld 70ae115bc7Smrj movl $18, %ecx 71ae115bc7Smrj rep 72ae115bc7Smrj movsb 73ae115bc7Smrj 74ae115bc7Smrj /* 75ae115bc7Smrj * Save system registers 76ae115bc7Smrj */ 77ae115bc7Smrj sidt save_idt 78ae115bc7Smrj sgdt save_gdt 79ae115bc7Smrj str save_tr 80ae115bc7Smrj movw %cs, save_cs 81ae115bc7Smrj movw %ds, save_ds 82ae115bc7Smrj movw %ss, save_ss 83ae115bc7Smrj movw %es, save_es 84ae115bc7Smrj movw %fs, save_fs 85ae115bc7Smrj movw %gs, save_gs 869b0bb795SJohn Levon movq %cr4, %rax 879b0bb795SJohn Levon movq %rax, save_cr4 889b0bb795SJohn Levon movq %cr3, %rax 899b0bb795SJohn Levon movq %rax, save_cr3 909b0bb795SJohn Levon movq %cr0, %rax 919b0bb795SJohn Levon movq %rax, save_cr0 92ae115bc7Smrj 93ae115bc7Smrj /* 94ae115bc7Smrj * save/clear the extension parts of the fs/gs base registers and cr8 95ae115bc7Smrj */ 96ae115bc7Smrj movl $MSR_AMD_FSBASE, %ecx 97ae115bc7Smrj rdmsr 98ae115bc7Smrj movl %eax, save_fsbase 99ae115bc7Smrj movl %edx, save_fsbase + 4 100ae115bc7Smrj xorl %eax, %eax 101ae115bc7Smrj xorl %edx, %edx 102ae115bc7Smrj wrmsr 103ae115bc7Smrj 104ae115bc7Smrj movl $MSR_AMD_GSBASE, %ecx 105ae115bc7Smrj rdmsr 106ae115bc7Smrj movl %eax, save_gsbase 107ae115bc7Smrj movl %edx, save_gsbase + 4 108ae115bc7Smrj xorl %eax, %eax 109ae115bc7Smrj xorl %edx, %edx 110ae115bc7Smrj wrmsr 111ae115bc7Smrj 112ae115bc7Smrj movl $MSR_AMD_KGSBASE, %ecx 113ae115bc7Smrj rdmsr 114ae115bc7Smrj movl %eax, save_kgsbase 115ae115bc7Smrj movl %edx, save_kgsbase + 4 116ae115bc7Smrj xorl %eax, %eax 117ae115bc7Smrj xorl %edx, %edx 118ae115bc7Smrj wrmsr 119ae115bc7Smrj 120ae115bc7Smrj movq %cr8, %rax 121ae115bc7Smrj movq %rax, save_cr8 122ae115bc7Smrj 123ae115bc7Smrj /* 124ae115bc7Smrj * set offsets in 16 bit ljmp instructions below 125ae115bc7Smrj */ 1269b0bb795SJohn Levon leaq enter_real, %rax 127ae115bc7Smrj movw %ax, enter_real_ljmp 128ae115bc7Smrj 1299b0bb795SJohn Levon leaq enter_protected, %rax 130ae115bc7Smrj movw %ax, enter_protected_ljmp 131ae115bc7Smrj 1329b0bb795SJohn Levon leaq gdt_info, %rax 133ae115bc7Smrj movw %ax, gdt_info_load 134ae115bc7Smrj 135ae115bc7Smrj /* 136ae115bc7Smrj * insert BIOS interrupt number into later instruction 137ae115bc7Smrj */ 138ae115bc7Smrj movb %bl, int_instr+1 139ae115bc7Smrj jmp 1f 140ae115bc7Smrj1: 141ae115bc7Smrj 142ae115bc7Smrj /* 143ae115bc7Smrj * zero out all the registers to make sure they're 16 bit clean 144ae115bc7Smrj */ 145ae115bc7Smrj xorq %r8, %r8 146ae115bc7Smrj xorq %r9, %r9 147ae115bc7Smrj xorq %r10, %r10 148ae115bc7Smrj xorq %r11, %r11 149ae115bc7Smrj xorq %r12, %r12 150ae115bc7Smrj xorq %r13, %r13 151ae115bc7Smrj xorq %r14, %r14 152ae115bc7Smrj xorq %r15, %r15 153ae115bc7Smrj xorl %eax, %eax 154ae115bc7Smrj xorl %ebx, %ebx 155ae115bc7Smrj xorl %ecx, %ecx 156ae115bc7Smrj xorl %edx, %edx 157ae115bc7Smrj xorl %ebp, %ebp 158ae115bc7Smrj xorl %esi, %esi 159ae115bc7Smrj xorl %edi, %edi 160ae115bc7Smrj 161ae115bc7Smrj /* 162ae115bc7Smrj * Load our own GDT/IDT 163ae115bc7Smrj */ 164ae115bc7Smrj lgdt gdt_info 165ae115bc7Smrj lidt idt_info 166ae115bc7Smrj 167ae115bc7Smrj /* 1689b0bb795SJohn Levon * Shut down 64 bit mode. First get into compatibility mode. 169ae115bc7Smrj */ 170ae115bc7Smrj movq %rsp, %rax 171ae115bc7Smrj pushq $B32DATA_SEL 172ae115bc7Smrj pushq %rax 173ae115bc7Smrj pushf 174ae115bc7Smrj pushq $B32CODE_SEL 175ae115bc7Smrj pushq $1f 176ae115bc7Smrj iretq 177ae115bc7Smrj1: 178ae115bc7Smrj .code32 179ae115bc7Smrj 180ae115bc7Smrj /* 181ae115bc7Smrj * disable long mode by: 182ae115bc7Smrj * - shutting down paging (bit 31 of cr0) 183ae115bc7Smrj * - flushing the TLB 184ae115bc7Smrj * - disabling LME (long made enable) in EFER (extended feature reg) 185ae115bc7Smrj */ 186ae115bc7Smrj movl %cr0, %eax 187ae115bc7Smrj btcl $31, %eax /* disable paging */ 188ae115bc7Smrj movl %eax, %cr0 189ae115bc7Smrj ljmp $B32CODE_SEL, $1f 190ae115bc7Smrj1: 191ae115bc7Smrj 192ae115bc7Smrj xorl %eax, %eax 193ae115bc7Smrj movl %eax, %cr3 /* flushes TLB */ 194ae115bc7Smrj 195ae115bc7Smrj movl $MSR_AMD_EFER, %ecx /* Extended Feature Enable */ 196ae115bc7Smrj rdmsr 197ae115bc7Smrj btcl $8, %eax /* bit 8 Long Mode Enable bit */ 198ae115bc7Smrj wrmsr 199ae115bc7Smrj 200ae115bc7Smrj /* 201ae115bc7Smrj * ok.. now enter 16 bit mode, so we can shut down protected mode 202ae115bc7Smrj * 203ae115bc7Smrj * We'll have to act like we're still in a 32 bit section. 204ae115bc7Smrj * So the code from this point has DATASZ in front of it to get 32 bit 205ae115bc7Smrj * operands. If DATASZ is missing the operands will be 16 bit. 206ae115bc7Smrj * 207ae115bc7Smrj * Now shut down paging and protected (ie. segmentation) modes. 208ae115bc7Smrj */ 209ae115bc7Smrj ljmp $B16CODE_SEL, $enter_16_bit 210ae115bc7Smrjenter_16_bit: 211ae115bc7Smrj 212ae115bc7Smrj /* 213ae115bc7Smrj * Make sure hidden parts of segment registers are 16 bit clean 214ae115bc7Smrj */ 215ae115bc7Smrj DATASZ movl $B16DATA_SEL, %eax 216ae115bc7Smrj movw %ax, %ss 217ae115bc7Smrj movw %ax, %ds 218ae115bc7Smrj movw %ax, %es 219ae115bc7Smrj movw %ax, %fs 220ae115bc7Smrj movw %ax, %gs 221ae115bc7Smrj 222ae115bc7Smrj 223ae115bc7Smrj DATASZ movl $0x0, %eax /* put us in real mode */ 224ae115bc7Smrj DATASZ movl %eax, %cr0 225ae115bc7Smrj .byte 0xea /* ljmp */ 226ae115bc7Smrjenter_real_ljmp: 227ae115bc7Smrj .value 0 /* addr (16 bit) */ 228ae115bc7Smrj .value 0x0 /* value for %cs */ 229ae115bc7Smrjenter_real: 230ae115bc7Smrj 231ae115bc7Smrj /* 232ae115bc7Smrj * zero out the remaining segment registers 233ae115bc7Smrj */ 234ae115bc7Smrj DATASZ xorl %eax, %eax 235ae115bc7Smrj movw %ax, %ss 236ae115bc7Smrj movw %ax, %ds 237ae115bc7Smrj movw %ax, %es 238ae115bc7Smrj movw %ax, %fs 239ae115bc7Smrj movw %ax, %gs 240ae115bc7Smrj 241ae115bc7Smrj /* 242ae115bc7Smrj * load the arguments to the BIOS call from the stack 243ae115bc7Smrj */ 244ae115bc7Smrj popl %eax /* really executes a 16 bit pop */ 245ae115bc7Smrj popl %ebx 246ae115bc7Smrj popl %ecx 247ae115bc7Smrj popl %edx 248ae115bc7Smrj popl %esi 249ae115bc7Smrj popl %edi 250ae115bc7Smrj popl %ebp 251ae115bc7Smrj pop %es 252ae115bc7Smrj pop %ds 253ae115bc7Smrj 254ae115bc7Smrj /* 255ae115bc7Smrj * do the actual BIOS call 256ae115bc7Smrj */ 257ae115bc7Smrj sti 258ae115bc7Smrjint_instr: 259ae115bc7Smrj int $0x10 /* this int number is overwritten */ 260ae115bc7Smrj cli /* ensure interrupts remain disabled */ 261ae115bc7Smrj 262ae115bc7Smrj /* 263ae115bc7Smrj * save results of the BIOS call 264ae115bc7Smrj */ 265ae115bc7Smrj pushf 266ae115bc7Smrj push %ds 267ae115bc7Smrj push %es 268ae115bc7Smrj pushl %ebp /* still executes as 16 bit */ 269ae115bc7Smrj pushl %edi 270ae115bc7Smrj pushl %esi 271ae115bc7Smrj pushl %edx 272ae115bc7Smrj pushl %ecx 273ae115bc7Smrj pushl %ebx 274ae115bc7Smrj pushl %eax 275ae115bc7Smrj 276ae115bc7Smrj /* 277ae115bc7Smrj * Restore protected mode and 32 bit execution 278ae115bc7Smrj */ 279ae115bc7Smrj push $0 /* make sure %ds is zero before lgdt */ 280ae115bc7Smrj pop %ds 281ae115bc7Smrj .byte 0x0f, 0x01, 0x16 /* lgdt */ 282ae115bc7Smrjgdt_info_load: 283ae115bc7Smrj .value 0 /* temp GDT in currently addressible mem */ 284ae115bc7Smrj 285ae115bc7Smrj DATASZ movl $0x1, %eax 286ae115bc7Smrj DATASZ movl %eax, %cr0 287ae115bc7Smrj 288ae115bc7Smrj .byte 0xea /* ljmp */ 289ae115bc7Smrjenter_protected_ljmp: 290ae115bc7Smrj .value 0 /* addr (still in 16 bit) */ 291ae115bc7Smrj .value B32CODE_SEL /* %cs value */ 292ae115bc7Smrjenter_protected: 293ae115bc7Smrj 294ae115bc7Smrj /* 295ae115bc7Smrj * We are now back in a 32 bit code section, fix data/stack segments 296ae115bc7Smrj */ 297ae115bc7Smrj .code32 298ae115bc7Smrj movw $B32DATA_SEL, %ax 299ae115bc7Smrj movw %ax, %ds 300ae115bc7Smrj movw %ax, %ss 301ae115bc7Smrj 302ae115bc7Smrj /* 303ae115bc7Smrj * Re-enable paging. Note we only use 32 bit mov's to restore these 304ae115bc7Smrj * control registers. That's OK as the upper 32 bits are always zero. 305ae115bc7Smrj */ 306ae115bc7Smrj movl save_cr4, %eax 307ae115bc7Smrj movl %eax, %cr4 308ae115bc7Smrj movl save_cr3, %eax 309ae115bc7Smrj movl %eax, %cr3 310ae115bc7Smrj 311ae115bc7Smrj /* 312ae115bc7Smrj * re-enable long mode 313ae115bc7Smrj */ 314ae115bc7Smrj movl $MSR_AMD_EFER, %ecx 315ae115bc7Smrj rdmsr 316ae115bc7Smrj btsl $8, %eax 317ae115bc7Smrj wrmsr 318ae115bc7Smrj 319ae115bc7Smrj movl save_cr0, %eax 320ae115bc7Smrj movl %eax, %cr0 321ae115bc7Smrj jmp enter_paging 322ae115bc7Smrjenter_paging: 323ae115bc7Smrj 324ae115bc7Smrj 325ae115bc7Smrj /* 326ae115bc7Smrj * transition back to 64 bit mode 327ae115bc7Smrj */ 328ae115bc7Smrj pushl $B64CODE_SEL 329ae115bc7Smrj pushl $longmode 330ae115bc7Smrj lret 331ae115bc7Smrjlongmode: 332ae115bc7Smrj .code64 333ae115bc7Smrj /* 334ae115bc7Smrj * restore caller frame pointer and segment registers 335ae115bc7Smrj */ 336ae115bc7Smrj lgdt save_gdt 337ae115bc7Smrj lidt save_idt 338ae115bc7Smrj 339ae115bc7Smrj /* 340ae115bc7Smrj * Before loading the task register we need to reset the busy bit 341ae115bc7Smrj * in its corresponding GDT selector. The busy bit is the 2nd bit in 342ae115bc7Smrj * the 5th byte of the selector. 343ae115bc7Smrj */ 344ae115bc7Smrj movzwq save_tr, %rax 345ae115bc7Smrj addq save_gdt+2, %rax 346ae115bc7Smrj btcl $1, 5(%rax) 347ae115bc7Smrj ltr save_tr 348ae115bc7Smrj movw save_ds, %ds 349ae115bc7Smrj movw save_ss, %ss 350ae115bc7Smrj movw save_es, %es 351ae115bc7Smrj movw save_fs, %fs 352ae115bc7Smrj movw save_gs, %gs 353ae115bc7Smrj 354ae115bc7Smrj pushq save_cs 355ae115bc7Smrj pushq $.newcs 356ae115bc7Smrj lretq 357ae115bc7Smrj.newcs: 358ae115bc7Smrj 359ae115bc7Smrj /* 360ae115bc7Smrj * restore the hidden kernel segment base register values 361ae115bc7Smrj */ 362ae115bc7Smrj movl save_fsbase, %eax 363ae115bc7Smrj movl save_fsbase + 4, %edx 364ae115bc7Smrj movl $MSR_AMD_FSBASE, %ecx 365ae115bc7Smrj wrmsr 366ae115bc7Smrj 367ae115bc7Smrj movl save_gsbase, %eax 368ae115bc7Smrj movl save_gsbase + 4, %edx 369ae115bc7Smrj movl $MSR_AMD_GSBASE, %ecx 370ae115bc7Smrj wrmsr 371ae115bc7Smrj 372ae115bc7Smrj movl save_kgsbase, %eax 373ae115bc7Smrj movl save_kgsbase + 4, %edx 374ae115bc7Smrj movl $MSR_AMD_KGSBASE, %ecx 375ae115bc7Smrj wrmsr 376ae115bc7Smrj 377ae115bc7Smrj movq save_cr8, %rax 378ae115bc7Smrj cmpq $0, %rax 379ae115bc7Smrj je 1f 380ae115bc7Smrj movq %rax, %cr8 381ae115bc7Smrj1: 382ae115bc7Smrj 383ae115bc7Smrj /* 384ae115bc7Smrj * copy results to caller's location, then restore remaining registers 385ae115bc7Smrj */ 386ae115bc7Smrj movq save_rsi, %rdi 387ae115bc7Smrj movq %rsp, %rsi 388ae115bc7Smrj movq $18, %rcx 389ae115bc7Smrj rep 390ae115bc7Smrj movsb 391ae115bc7Smrj movw 18(%rsp), %ax 392ae115bc7Smrj andq $0xffff, %rax 393ae115bc7Smrj movq save_r12, %r12 394ae115bc7Smrj movq save_r13, %r13 395ae115bc7Smrj movq save_r14, %r14 396ae115bc7Smrj movq save_r15, %r15 397ae115bc7Smrj movq save_rbx, %rbx 398ae115bc7Smrj movq save_rbp, %rbp 399ae115bc7Smrj movq save_rsp, %rsp 400ae115bc7Smrj ret 401ae115bc7Smrj 402ae115bc7Smrj 403ae115bc7Smrj/* 404ae115bc7Smrj * Caller's registers to restore 405ae115bc7Smrj */ 406ae115bc7Smrj .align 4 407ae115bc7Smrjsave_esi: 408ae115bc7Smrj .long 0 409ae115bc7Smrjsave_edi: 410ae115bc7Smrj .long 0 411ae115bc7Smrjsave_ebx: 412ae115bc7Smrj .long 0 413ae115bc7Smrjsave_ebp: 414ae115bc7Smrj .long 0 415ae115bc7Smrjsave_esp: 416ae115bc7Smrj .long 0 417ae115bc7Smrj 418ae115bc7Smrj .align 8 419ae115bc7Smrjsave_rsi: 420ae115bc7Smrj .quad 0 421ae115bc7Smrjsave_rbx: 422ae115bc7Smrj .quad 0 423ae115bc7Smrjsave_rbp: 424ae115bc7Smrj .quad 0 425ae115bc7Smrjsave_rsp: 426ae115bc7Smrj .quad 0 427ae115bc7Smrjsave_r12: 428ae115bc7Smrj .quad 0 429ae115bc7Smrjsave_r13: 430ae115bc7Smrj .quad 0 431ae115bc7Smrjsave_r14: 432ae115bc7Smrj .quad 0 433ae115bc7Smrjsave_r15: 434ae115bc7Smrj .quad 0 435ae115bc7Smrjsave_kgsbase: 436ae115bc7Smrj .quad 0 437ae115bc7Smrjsave_gsbase: 438ae115bc7Smrj .quad 0 439ae115bc7Smrjsave_fsbase: 440ae115bc7Smrj .quad 0 441ae115bc7Smrjsave_cr8: 442ae115bc7Smrj .quad 0 443ae115bc7Smrj 444ae115bc7Smrjsave_idt: 445ae115bc7Smrj .quad 0 446ae115bc7Smrj .quad 0 447ae115bc7Smrj 448ae115bc7Smrjsave_gdt: 449ae115bc7Smrj .quad 0 450ae115bc7Smrj .quad 0 451ae115bc7Smrj 452ae115bc7Smrjsave_cr0: 453ae115bc7Smrj .quad 0 454ae115bc7Smrjsave_cr3: 455ae115bc7Smrj .quad 0 456ae115bc7Smrjsave_cr4: 457ae115bc7Smrj .quad 0 458ae115bc7Smrjsave_cs: 459ae115bc7Smrj .quad 0 460ae115bc7Smrjsave_ss: 461ae115bc7Smrj .value 0 462ae115bc7Smrjsave_ds: 463ae115bc7Smrj .value 0 464ae115bc7Smrjsave_es: 465ae115bc7Smrj .value 0 466ae115bc7Smrjsave_fs: 467ae115bc7Smrj .value 0 468ae115bc7Smrjsave_gs: 469ae115bc7Smrj .value 0 470ae115bc7Smrjsave_tr: 471ae115bc7Smrj .value 0 472ae115bc7Smrj 473ae115bc7Smrjidt_info: 474ae115bc7Smrj .value 0x3ff 475ae115bc7Smrj .quad 0 476ae115bc7Smrj 477ae115bc7Smrj 478ae115bc7Smrj/* 479ae115bc7Smrj * We need to trampoline thru a gdt we have in low memory. 480ae115bc7Smrj */ 481ae115bc7Smrj#include "../boot/boot_gdt.s" 482