sys/cpu/x86_64/include/asmacros.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | /* * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 2008 The DragonFly Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/sys/amd64/include/asmacros.h,v 1.32 2006/10/28 06:04:29 bde Exp $ */ #ifndef _CPU_ASMACROS_H_ #define _CPU_ASMACROS_H_ #include <sys/cdefs.h> #include <machine/specialreg.h> /* XXX too much duplication in various asm*.h's. */ /* * CNAME is used to manage the relationship between symbol names in C * and the equivalent assembly language names. CNAME is given a name as * it would be used in a C program. It expands to the equivalent assembly * language name. */ #define CNAME(csym) csym #define ALIGN_DATA .p2align 3 /* 8 byte alignment, zero filled */ #define ALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ #define SUPERALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ #define GEN_ENTRY(name) ALIGN_TEXT; .globl CNAME(name); \ .type CNAME(name),@function; CNAME(name): #define NON_GPROF_ENTRY(name) GEN_ENTRY(name) #define NON_GPROF_RET .byte 0xc3 /* opcode for `ret' */ #define END(name) .size name, . - name /* * ALTENTRY() has to align because it is before a corresponding ENTRY(). * ENTRY() has to align to because there may be no ALTENTRY() before it. * If there is a previous ALTENTRY() then the alignment code for ENTRY() * is empty. */ #define ALTENTRY(name) GEN_ENTRY(name) #define CROSSJUMP(jtrue, label, jfalse) jtrue label #define CROSSJUMPTARGET(label) #define ENTRY(name) GEN_ENTRY(name) #define FAKE_MCOUNT(caller) #define MCOUNT #define MCOUNT_LABEL(name) #define MEXITCOUNT #ifdef LOCORE /* * Convenience macro for declaring interrupt entry points. */ #define IDTVEC(name) ALIGN_TEXT; .globl __CONCAT(X,name); \ .type __CONCAT(X,name),@function; __CONCAT(X,name): /* * stack frame macro support - supports mmu isolation, swapgs, and * stack frame pushing and popping. */ /* * Kernel pmap isolation to work-around the massive Intel mmu bug * that allows kernel memory to be sussed out due to speculative memory * reads and instruction execution creating timing differences that can * be detected by userland. e.g. force speculative read, speculatively * execute a cmp/branch sequence, detect timing. Iterate cmp $values * to suss-out content of speculatively read kernel memory. * * We do this by creating a trampoline area for all user->kernel and * kernel->user transitions. The trampoline area allows us to limit * the reach the kernel map in the isolated version of the user pmap * to JUST the trampoline area (for all cpus), tss, and vector area. * * It is very important that these transitions not access any memory * outside of the trampoline page while the isolated user process pmap * is active in %cr3. * * The trampoline does not add much overhead when pmap isolation is * disabled, so we just run with it regardless. Of course, when pmap * isolation is enabled, the %cr3 loads add 150-250ns to every system * call as well as (without PCID) smash the TLB. * * KMMUENTER - Executed by the trampoline when a user->kernel transition * is detected. The stack pointer points into the pcpu * trampoline space and is available for register save/restore. * Other registers have not yet been saved. %gs points at * the kernel pcpu structure. * * Caller has already determined that a transition is in * progress and has already issued the swapgs. hwtf indicates * how much hardware has already pushed. * * KMMUEXIT - Executed when a kernel->user transition is made. The stack * pointer points into the pcpu trampoline space and we are * almost ready to iretq. %gs still points at the kernel pcpu * structure. * * Caller has already determined that a transition is in * progress. hwtf indicates how much hardware has already * pushed. */ /* * KMMUENTER_CORE - Handles ISOMMU, IBRS, and IBPB. Caller has already * saved %rcx and %rdx. We have to deal with %rax. * * XXX If IBPB is not supported, try to clear the * call return hw cache w/ many x chained call sequence? * * NOTE - IBRS2 - We are leaving IBRS on full-time. However, Intel * believes it is not safe unless the MSR is poked on each * user->kernel transition, so poke the MSR for both IBRS1 * and IBRS2. */ #define KMMUENTER_CORE \ testq $PCB_ISOMMU,PCPU(trampoline)+TR_PCB_FLAGS ; \ je 40f ; \ movq PCPU(trampoline)+TR_PCB_CR3,%rcx ; \ movq %rcx,%cr3 ; \ 40: movl PCPU(trampoline)+TR_PCB_SPEC_CTRL,%edx ; \ testq %rdx, %rdx ; \ je 43f ; \ movq %rax, PCPU(trampoline)+TR_RAX ; \ testq $SPEC_CTRL_DUMMY_ENABLE,%rdx ; \ je 41f ; \ movq %rdx, %rax ; \ andq $SPEC_CTRL_IBRS|SPEC_CTRL_STIBP, %rax ; \ movq $MSR_SPEC_CTRL,%rcx ; \ xorl %edx,%edx ; \ wrmsr ; \ movl PCPU(trampoline)+TR_PCB_SPEC_CTRL,%edx ; \ 41: testq $SPEC_CTRL_DUMMY_IBPB,%rdx ; \ je 42f ; \ movl $MSR_PRED_CMD,%ecx ; \ movl $1,%eax ; \ xorl %edx,%edx ; \ wrmsr ; \ 42: movq PCPU(trampoline)+TR_RAX, %rax ; \ 43: \ /* * Enter with trampoline, hardware pushed up to %rip */ #define KMMUENTER_TFRIP \ subq $TR_RIP, %rsp ; \ movq %rcx, TR_RCX(%rsp) ; \ movq %rdx, TR_RDX(%rsp) ; \ KMMUENTER_CORE ; \ movq %rsp, %rcx ; /* trampoline rsp */ \ movq PCPU(trampoline)+TR_PCB_RSP,%rsp ; /* kstack rsp */ \ movq TR_SS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RSP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RFLAGS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_CS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RIP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RDX(%rcx), %rdx ; \ movq TR_RCX(%rcx), %rcx \ /* * Enter with trampoline, hardware pushed up to ERR */ #define KMMUENTER_TFERR \ subq $TR_ERR, %rsp ; \ movq %rcx, TR_RCX(%rsp) ; \ movq %rdx, TR_RDX(%rsp) ; \ KMMUENTER_CORE ; \ movq %rsp, %rcx ; /* trampoline rsp */ \ movq PCPU(trampoline)+TR_PCB_RSP,%rsp ; /* kstack rsp */ \ movq TR_SS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RSP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RFLAGS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_CS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RIP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_ERR(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RDX(%rcx), %rdx ; \ movq TR_RCX(%rcx), %rcx \ /* * Enter with trampoline, hardware pushed up to ERR and * we need to save %cr2 early (before potentially reloading %cr3). */ #define KMMUENTER_TFERR_SAVECR2 \ subq $TR_ERR, %rsp ; \ movq %rcx, TR_RCX(%rsp) ; \ movq %rdx, TR_RDX(%rsp) ; \ movq %cr2, %rcx ; \ movq %rcx, PCPU(trampoline)+TR_CR2 ; \ KMMUENTER_CORE ; \ movq %rsp, %rcx ; /* trampoline rsp */ \ movq PCPU(trampoline)+TR_PCB_RSP,%rsp ; /* kstack rsp */ \ movq TR_SS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RSP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RFLAGS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_CS(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RIP(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_ERR(%rcx), %rdx ; \ pushq %rdx ; \ movq TR_RDX(%rcx), %rdx ; \ movq TR_RCX(%rcx), %rcx \ /* * Set %cr3 if necessary on syscall entry. No registers may be * disturbed. * * NOTE: TR_CR2 is used by the caller to save %rsp, we cannot use it here. */ #define KMMUENTER_SYSCALL \ movq %rcx, PCPU(trampoline)+TR_RCX ; \ movq %rdx, PCPU(trampoline)+TR_RDX ; \ KMMUENTER_CORE ; \ movq PCPU(trampoline)+TR_RDX, %rdx ; \ movq PCPU(trampoline)+TR_RCX, %rcx \ /* * KMMUEXIT_CORE handles IBRS, STIBP, and MDS, but not ISOMMU * * We don't re-execute the IBPB barrier on exit atm. * * The MDS barrier (Microarchitectural Data Sampling) should be executed * prior to any return to user-mode, if supported and enabled. This is * Intel-only. * * WARNING! %rsp may not be usable (it could be pointing to the user * stack at this point). And we must save/restore any registers * we use. */ #define KMMUEXIT_CORE \ testl $SPEC_CTRL_DUMMY_ENABLE|SPEC_CTRL_MDS_ENABLE, PCPU(trampoline)+TR_PCB_SPEC_CTRL+4 ; \ je 43f ; \ movq %rax, PCPU(trampoline)+TR_RAX ; \ movl PCPU(trampoline)+TR_PCB_SPEC_CTRL+4, %eax ; \ testq $SPEC_CTRL_MDS_ENABLE, %rax ; \ je 41f ; \ movq $GSEL(GDATA_SEL, SEL_KPL), PCPU(trampoline)+TR_RCX ; \ verw PCPU(trampoline)+TR_RCX ; \ 41: testq $SPEC_CTRL_DUMMY_ENABLE, %rax ; \ je 42f ; \ movq %rcx, PCPU(trampoline)+TR_RCX ; \ movq %rdx, PCPU(trampoline)+TR_RDX ; \ andq $SPEC_CTRL_IBRS|SPEC_CTRL_STIBP, %rax ; \ movq $MSR_SPEC_CTRL,%rcx ; \ xorl %edx,%edx ; \ wrmsr ; \ movq PCPU(trampoline)+TR_RDX, %rdx ; \ movq PCPU(trampoline)+TR_RCX, %rcx ; \ 42: movq PCPU(trampoline)+TR_RAX, %rax ; \ 43: /* * We are positioned at the base of the trapframe. Advance the trapframe * and handle MMU isolation. MMU isolation requires us to copy the * hardware frame to the trampoline area before setting %cr3 to the * isolated map. We then set the %rsp for iretq to TR_RIP in the * trampoline area (after restoring the register we saved in TR_ERR). */ #define KMMUEXIT \ addq $TF_RIP,%rsp ; \ KMMUEXIT_CORE ; \ testq $PCB_ISOMMU,PCPU(trampoline)+TR_PCB_FLAGS ; \ je 50f ; \ movq %rcx, PCPU(trampoline)+TR_ERR ; /* save in TR_ERR */ \ popq %rcx ; /* copy %rip */ \ movq %rcx, PCPU(trampoline)+TR_RIP ; \ popq %rcx ; /* copy %cs */ \ movq %rcx, PCPU(trampoline)+TR_CS ; \ popq %rcx ; /* copy %rflags */ \ movq %rcx, PCPU(trampoline)+TR_RFLAGS ; \ popq %rcx ; /* copy %rsp */ \ movq %rcx, PCPU(trampoline)+TR_RSP ; \ popq %rcx ; /* copy %ss */ \ movq %rcx, PCPU(trampoline)+TR_SS ; \ movq %gs:0,%rcx ; \ addq $GD_TRAMPOLINE+TR_ERR,%rcx ; \ movq %rcx,%rsp ; \ movq PCPU(trampoline)+TR_PCB_CR3_ISO,%rcx ; \ movq %rcx,%cr3 ; \ popq %rcx ; /* positioned at TR_RIP after this */ \ 50: \ /* * Warning: user stack pointer already loaded into %rsp at this * point. We still have the kernel %gs. * * Caller will sysexit, we do not have to copy anything to the * trampoline area. */ #define KMMUEXIT_SYSCALL \ KMMUEXIT_CORE ; \ testq $PCB_ISOMMU,PCPU(trampoline)+TR_PCB_FLAGS ; \ je 50f ; \ movq %rcx, PCPU(trampoline)+TR_RCX ; \ movq PCPU(trampoline)+TR_PCB_CR3_ISO,%rcx ; \ movq %rcx,%cr3 ; \ movq PCPU(trampoline)+TR_RCX, %rcx ; \ 50: \ /* * Macros to create and destroy a trap frame. rsp has already been shifted * to the base of the trapframe in the thread structure. */ #define PUSH_FRAME_REGS \ movq %rdi,TF_RDI(%rsp) ; \ movq %rsi,TF_RSI(%rsp) ; \ movq %rdx,TF_RDX(%rsp) ; \ movq %rcx,TF_RCX(%rsp) ; \ movq %r8,TF_R8(%rsp) ; \ movq %r9,TF_R9(%rsp) ; \ movq %rax,TF_RAX(%rsp) ; \ movq %rbx,TF_RBX(%rsp) ; \ movq %rbp,TF_RBP(%rsp) ; \ movq %r10,TF_R10(%rsp) ; \ movq %r11,TF_R11(%rsp) ; \ movq %r12,TF_R12(%rsp) ; \ movq %r13,TF_R13(%rsp) ; \ movq %r14,TF_R14(%rsp) ; \ movq %r15,TF_R15(%rsp) ; \ /* SECURITY CLEAR REGS */ \ xorq %rax,%rax ; \ movq %rax,%rbx ; \ movq %rax,%rcx ; \ movq %rax,%rdx ; \ movq %rax,%rdi ; \ movq %rax,%rsi ; \ movq %rax,%rbp ; \ movq %rax,%r8 ; \ movq %rax,%r9 ; \ movq %rax,%r10 ; \ movq %rax,%r11 ; \ movq %rax,%r12 ; \ movq %rax,%r13 ; \ movq %rax,%r14 ; \ movq %rax,%r15 \ /* * PUSH_FRAME is the first thing executed upon interrupt entry. We are * responsible for swapgs execution and the KMMUENTER dispatch. * * NOTE - PUSH_FRAME code doesn't mess with %gs or the stack, or assume it can * use PCPU(trampoline), if the trap/exception is from supevisor mode. * It only messes with that stuff when the trap/exception is from user * mode. Our DBG and NMI code depend on this behavior. */ #define PUSH_FRAME_TFRIP \ testb $SEL_RPL_MASK,TF_CS-TF_RIP(%rsp) ; /* from userland? */ \ jz 1f ; \ swapgs ; /* from userland */ \ KMMUENTER_TFRIP ; /* from userland */ \ 1: \ subq $TF_RIP,%rsp ; \ PUSH_FRAME_REGS ; \ SMAP_CLOSE \ #define PUSH_FRAME_TFERR \ testb $SEL_RPL_MASK,TF_CS-TF_ERR(%rsp) ; /* from userland? */ \ jz 1f ; \ swapgs ; /* from userland */ \ KMMUENTER_TFERR ; /* from userland */ \ 1: \ subq $TF_ERR,%rsp ; \ PUSH_FRAME_REGS ; \ SMAP_CLOSE \ #define PUSH_FRAME_TFERR_SAVECR2 \ testb $SEL_RPL_MASK,TF_CS-TF_ERR(%rsp) ; \ jz 1f ; \ swapgs ; /* from userland */ \ KMMUENTER_TFERR_SAVECR2 ;/* from userland */ \ subq $TF_ERR,%rsp ; \ PUSH_FRAME_REGS ; \ movq PCPU(trampoline)+TR_CR2, %r10 ; \ jmp 2f ; \ 1: \ subq $TF_ERR,%rsp ; \ PUSH_FRAME_REGS ; \ movq %cr2, %r10 ; \ 2: \ movq %r10, TF_ADDR(%rsp) ; \ SMAP_CLOSE \ /* * POP_FRAME is issued just prior to the iretq, or just prior to a * jmp doreti_iret. These must be passed in to the macro. */ #define POP_FRAME(lastinsn) \ movq TF_RDI(%rsp),%rdi ; \ movq TF_RSI(%rsp),%rsi ; \ movq TF_RDX(%rsp),%rdx ; \ movq TF_RCX(%rsp),%rcx ; \ movq TF_R8(%rsp),%r8 ; \ movq TF_R9(%rsp),%r9 ; \ movq TF_RAX(%rsp),%rax ; \ movq TF_RBX(%rsp),%rbx ; \ movq TF_RBP(%rsp),%rbp ; \ movq TF_R10(%rsp),%r10 ; \ movq TF_R11(%rsp),%r11 ; \ movq TF_R12(%rsp),%r12 ; \ movq TF_R13(%rsp),%r13 ; \ movq TF_R14(%rsp),%r14 ; \ movq TF_R15(%rsp),%r15 ; \ cli ; \ testb $SEL_RPL_MASK,TF_CS(%rsp) ; /* return to user? */ \ jz 1f ; \ KMMUEXIT ; /* return to user */ \ swapgs ; /* return to user */ \ jmp 2f ; \ 1: \ addq $TF_RIP,%rsp ; /* setup for iretq */ \ 2: \ lastinsn /* * Access per-CPU data. */ #define PCPU(member) %gs:gd_ ## member #define PCPU_E8(member,idx) %gs:gd_ ## member(,idx,8) #define PCPU_ADDR(member, reg) \ movq %gs:PC_PRVSPACE, reg ; \ addq $PC_ ## member, reg /* * This adds a code placemarker (the 3-byte NOP) and references * it from a section, allowing it to be replaced with a STAC or CLAC * instruction (also 3-byte instructions) when the system supports * SMAP. */ #define SMAP_OPEN \ .globl __start_set_smap_open ; \ .globl __stop_set_smap_open ; \ 60: nop %eax ; \ .section set_smap_open,"aw" ; \ .quad 60b ; \ .previous \ #define SMAP_CLOSE \ .globl __start_set_smap_close ; \ .globl __stop_set_smap_close ; \ 60: nop %eax ; \ .section set_smap_close,"aw" ; \ .quad 60b ; \ .previous \ #endif /* LOCORE */ #endif /* !_CPU_ASMACROS_H_ */ |