Home | History | Annotate | Line # | Download | only in amd64
      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