1 /* $NetBSD: cpufunc.S,v 1.70 2025/09/06 02:53:22 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2007, 2008, 2020, 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum, and by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/errno.h> 33 34 #include <machine/asm.h> 35 #include <machine/frameasm.h> 36 #include <machine/specialreg.h> 37 #include <machine/segments.h> 38 39 #include "opt_dtrace.h" 40 #include "opt_xen.h" 41 #include "opt_svs.h" 42 43 #include "assym.h" 44 45 /* Small and slow, so align less. */ 46 #undef _ALIGN_TEXT 47 #define _ALIGN_TEXT .align 8 48 49 ENTRY(x86_lfence) 50 lfence 51 ret 52 END(x86_lfence) 53 54 ENTRY(x86_sfence) 55 sfence 56 ret 57 END(x86_sfence) 58 59 ENTRY(x86_mfence) 60 mfence 61 ret 62 END(x86_mfence) 63 64 ENTRY(paravirt_membar_sync) 65 /* 66 * Store-before-load ordering with respect to matching logic 67 * on the hypervisor side. 68 * 69 * This is the same as membar_sync, but without hotpatching 70 * away the LOCK prefix on uniprocessor boots -- because under 71 * virtualization, we still have to coordinate with a `device' 72 * backed by a hypervisor that is potentially on another 73 * physical CPU even if we observe only one virtual CPU as the 74 * guest. 75 * 76 * See common/lib/libc/arch/x86_64/atomic/atomic.S for 77 * rationale and keep this in sync with the implementation 78 * of membar_sync there. 79 */ 80 lock 81 addq $0,-8(%rsp) 82 ret 83 END(paravirt_membar_sync) 84 85 #ifdef XEN 86 STRONG_ALIAS(xen_mb,paravirt_membar_sync) 87 #endif /* XEN */ 88 89 #ifdef KDTRACE_HOOKS 90 ENTRY(dtrace_smap_enable) 91 # ifndef XENPV 92 SMAP_ENABLE 93 # endif 94 ret 95 END(dtrace_smap_enable) 96 97 ENTRY(dtrace_smap_disable) 98 # ifndef XENPV 99 SMAP_DISABLE 100 # endif 101 ret 102 END(dtrace_smap_disable) 103 #endif 104 105 #ifndef XENPV 106 ENTRY(invlpg) 107 #ifdef SVS 108 movb _C_LABEL(svs_pcid),%al 109 testb %al,%al 110 jz 1f 111 pushq %rdi 112 pushq $PMAP_PCID_USER 113 movq $INVPCID_ADDRESS,%rax 114 invpcid (%rsp),%rax 115 addq $16,%rsp 116 1: /* FALLTHROUGH */ 117 #endif 118 invlpg (%rdi) 119 ret 120 END(invlpg) 121 122 ENTRY(lgdt) 123 /* Reload the descriptor table. */ 124 movq %rdi,%rax 125 lgdt (%rax) 126 /* Flush the prefetch queue. */ 127 jmp 1f 128 nop 129 1: jmp _C_LABEL(lgdt_finish) 130 END(lgdt) 131 132 ENTRY(lidt) 133 lidt (%rdi) 134 ret 135 END(lidt) 136 137 ENTRY(lldt) 138 cmpl %edi, CPUVAR(CURLDT) 139 jne 1f 140 ret 141 1: 142 movl %edi, CPUVAR(CURLDT) 143 lldt %di 144 ret 145 END(lldt) 146 147 ENTRY(ltr) 148 ltr %di 149 ret 150 END(ltr) 151 152 ENTRY(tlbflushg) 153 movq %cr4, %rax 154 testq $CR4_PGE, %rax 155 jz tlbflush 156 movq %rax, %rdx 157 andq $~CR4_PGE, %rdx 158 movq %rdx, %cr4 159 movq %rax, %cr4 160 ret 161 END(tlbflushg) 162 163 ENTRY(tlbflush) 164 #ifdef SVS 165 movb _C_LABEL(svs_pcid),%al 166 testb %al,%al 167 jz 1f 168 xorq %rax,%rax 169 pushq %rax 170 pushq %rax 171 movq $INVPCID_ALL_NONGLOBAL,%rax 172 invpcid (%rsp),%rax 173 addq $16,%rsp 174 ret 175 #endif 176 1: movq %cr3, %rax 177 movq %rax, %cr3 178 ret 179 END(tlbflush) 180 181 ENTRY(wbinvd) 182 wbinvd 183 ret 184 END(wbinvd) 185 186 ENTRY(setusergs) 187 CLI(ax) 188 swapgs 189 movw %di, %gs 190 swapgs 191 STI(ax) 192 ret 193 END(setusergs) 194 195 ENTRY(x86_read_flags) 196 pushfq 197 popq %rax 198 KMSAN_INIT_RET(8) 199 ret 200 END(x86_read_flags) 201 202 STRONG_ALIAS(x86_read_psl,x86_read_flags) 203 204 ENTRY(x86_write_flags) 205 pushq %rdi 206 popfq 207 ret 208 END(x86_write_flags) 209 210 STRONG_ALIAS(x86_write_psl,x86_write_flags) 211 212 ENTRY(smap_enable) 213 SMAP_ENABLE 214 ret 215 END(smap_enable) 216 217 ENTRY(smap_disable) 218 SMAP_DISABLE 219 ret 220 END(smap_disable) 221 222 /* 223 * %rdi = name 224 * %rsi = sel 225 */ 226 ENTRY(x86_hotpatch) 227 /* save RFLAGS, and disable intrs */ 228 pushfq 229 cli 230 231 /* save CR0, and disable WP */ 232 movq %cr0,%rcx 233 pushq %rcx 234 andq $~CR0_WP,%rcx 235 movq %rcx,%cr0 236 237 callq _C_LABEL(x86_hotpatch_apply) 238 239 /* write back and invalidate cache */ 240 wbinvd 241 242 /* restore CR0 */ 243 popq %rcx 244 movq %rcx,%cr0 245 246 /* flush instruction pipeline */ 247 pushq %rax 248 callq x86_flush 249 popq %rax 250 251 /* clean up */ 252 movq %rax,%rdi 253 callq _C_LABEL(x86_hotpatch_cleanup) 254 255 /* restore RFLAGS */ 256 popfq 257 ret 258 END(x86_hotpatch) 259 #endif /* !XENPV */ 260 261 /* 262 * cpu_counter and cpu_counter32 could be exact same, but KMSAN needs to have 263 * the correct size of the return value. 264 */ 265 #define SERIALIZE_lfence lfence 266 #define SERIALIZE_mfence mfence 267 268 #define ADD_counter32 addl CPUVAR(CC_SKEW), %eax 269 #define ADD_counter shlq $32, %rdx ;\ 270 orq %rdx, %rax ;\ 271 addq CPUVAR(CC_SKEW), %rax 272 273 #define RSIZE_counter32 4 274 #define RSIZE_counter 8 275 276 #define CPU_COUNTER_FENCE(counter, fence) \ 277 ENTRY(cpu_ ## counter ## _ ## fence) ;\ 278 movq CPUVAR(CURLWP), %rcx ;\ 279 leaq L_RU+RU_NIVCSW(%rcx), %rcx ;\ 280 1: ;\ 281 movq (%rcx), %rdi ;\ 282 SERIALIZE_ ## fence ;\ 283 rdtsc ;\ 284 ADD_ ## counter ;\ 285 cmpq %rdi, (%rcx) ;\ 286 jne 2f ;\ 287 KMSAN_INIT_RET(RSIZE_ ## counter) ;\ 288 ret ;\ 289 2: ;\ 290 jmp 1b ;\ 291 END(cpu_ ## counter ## _ ## fence) 292 293 CPU_COUNTER_FENCE(counter, lfence) 294 CPU_COUNTER_FENCE(counter, mfence) 295 CPU_COUNTER_FENCE(counter32, lfence) 296 CPU_COUNTER_FENCE(counter32, mfence) 297 298 #define CPU_COUNTER_CPUID(counter) \ 299 ENTRY(cpu_ ## counter ## _cpuid) ;\ 300 movq %rbx, %r9 ;\ 301 movq CPUVAR(CURLWP), %r8 ;\ 302 leaq L_RU+RU_NIVCSW(%r8), %r8 ;\ 303 1: ;\ 304 movq (%r8), %rdi ;\ 305 xor %eax, %eax ;\ 306 cpuid ;\ 307 rdtsc ;\ 308 ADD_ ## counter ;\ 309 cmpq %rdi, (%r8) ;\ 310 jne 2f ;\ 311 movq %r9, %rbx ;\ 312 KMSAN_INIT_RET(RSIZE_ ## counter) ;\ 313 ret ;\ 314 2: ;\ 315 jmp 1b ;\ 316 END(cpu_ ## counter ## _cpuid) 317 318 CPU_COUNTER_CPUID(counter) 319 CPU_COUNTER_CPUID(counter32) 320 321 ENTRY(rdmsr_safe) 322 movq CPUVAR(CURLWP), %r8 323 movq L_PCB(%r8), %r8 324 movq $_C_LABEL(msr_onfault), PCB_ONFAULT(%r8) 325 326 movl %edi, %ecx 327 rdmsr 328 salq $32, %rdx 329 movl %eax, %eax /* zero-extend %eax -> %rax */ 330 orq %rdx, %rax 331 movq %rax, (%rsi) 332 333 xorq %rax, %rax 334 movq %rax, PCB_ONFAULT(%r8) 335 #ifdef KMSAN 336 movq %rsi,%rdi 337 movq $8,%rsi 338 xorq %rdx,%rdx 339 callq _C_LABEL(kmsan_mark) 340 #endif 341 KMSAN_INIT_RET(4) 342 ret 343 END(rdmsr_safe) 344 345 ENTRY(msr_onfault) 346 movq CPUVAR(CURLWP), %r8 347 movq L_PCB(%r8), %r8 348 movq $0, PCB_ONFAULT(%r8) 349 movl $EFAULT, %eax 350 ret 351 END(msr_onfault) 352 353 ENTRY(breakpoint) 354 pushq %rbp 355 movq %rsp, %rbp 356 int $0x03 /* paranoid, not 'int3' */ 357 leave 358 ret 359 END(breakpoint) 360 361 ENTRY(x86_curcpu) 362 movq %gs:(CPU_INFO_SELF), %rax 363 KMSAN_INIT_RET(8) 364 ret 365 END(x86_curcpu) 366 367 ENTRY(x86_curlwp) 368 movq %gs:(CPU_INFO_CURLWP), %rax 369 KMSAN_INIT_RET(8) 370 ret 371 END(x86_curlwp) 372 373 ENTRY(__byte_swap_u32_variable) 374 movl %edi, %eax 375 bswapl %eax 376 KMSAN_INIT_RET(4) 377 ret 378 END(__byte_swap_u32_variable) 379 380 ENTRY(__byte_swap_u16_variable) 381 movl %edi, %eax 382 xchgb %al, %ah 383 KMSAN_INIT_RET(2) 384 ret 385 END(__byte_swap_u16_variable) 386 387 /* 388 * Reload segments after a GDT change. 389 */ 390 ENTRY(lgdt_finish) 391 movl $GSEL(GDATA_SEL, SEL_KPL),%eax 392 movl %eax,%ds 393 movl %eax,%es 394 movl %eax,%ss 395 jmp _C_LABEL(x86_flush) 396 END(lgdt_finish) 397 398 /* 399 * Flush instruction pipelines by doing an intersegment (far) return. 400 */ 401 ENTRY(x86_flush) 402 popq %rax 403 pushq $GSEL(GCODE_SEL, SEL_KPL) 404 pushq %rax 405 lretq 406 END(x86_flush) 407 408 /* Waits - set up stack frame. */ 409 ENTRY(x86_hlt) 410 pushq %rbp 411 movq %rsp, %rbp 412 hlt 413 leave 414 ret 415 END(x86_hlt) 416 417 /* Waits - set up stack frame. */ 418 ENTRY(x86_stihlt) 419 pushq %rbp 420 movq %rsp, %rbp 421 sti 422 hlt 423 leave 424 ret 425 END(x86_stihlt) 426 427 ENTRY(x86_monitor) 428 movq %rdi, %rax 429 movq %rsi, %rcx 430 monitor %rax, %rcx, %rdx 431 ret 432 END(x86_monitor) 433 434 /* Waits - set up stack frame. */ 435 ENTRY(x86_mwait) 436 pushq %rbp 437 movq %rsp, %rbp 438 movq %rdi, %rax 439 movq %rsi, %rcx 440 mwait %rax, %rcx 441 leave 442 ret 443 END(x86_mwait) 444 445 ENTRY(stts) 446 movq %cr0, %rax 447 orq $CR0_TS, %rax 448 movq %rax, %cr0 449 ret 450 END(stts) 451 452 ENTRY(fldummy) 453 ffree %st(7) 454 fldz 455 ret 456 END(fldummy) 457 458 ENTRY(inb) 459 movq %rdi, %rdx 460 xorq %rax, %rax 461 inb %dx, %al 462 KMSAN_INIT_RET(1) 463 ret 464 END(inb) 465 466 ENTRY(inw) 467 movq %rdi, %rdx 468 xorq %rax, %rax 469 inw %dx, %ax 470 KMSAN_INIT_RET(2) 471 ret 472 END(inw) 473 474 ENTRY(inl) 475 movq %rdi, %rdx 476 xorq %rax, %rax 477 inl %dx, %eax 478 KMSAN_INIT_RET(4) 479 ret 480 END(inl) 481 482 ENTRY(outb) 483 movq %rdi, %rdx 484 movq %rsi, %rax 485 outb %al, %dx 486 ret 487 END(outb) 488 489 ENTRY(outw) 490 movq %rdi, %rdx 491 movq %rsi, %rax 492 outw %ax, %dx 493 ret 494 END(outw) 495 496 ENTRY(outl) 497 movq %rdi, %rdx 498 movq %rsi, %rax 499 outl %eax, %dx 500 ret 501 END(outl) 502 503 /* 504 * Used by SVS only, to make an atomic but fast copy. Doesn't have 505 * sanitizer instrumentation, but sanitizers disable SVS, so no problem. 506 */ 507 ENTRY(svs_quad_copy) 508 movq %rdx,%rcx 509 rep 510 movsq 511 ret 512 END(svs_quad_copy) 513