summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64/apic_vector.S
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-08-30 07:59:49 +0000
committerkib <kib@FreeBSD.org>2013-08-30 07:59:49 +0000
commita2b5da0090b331918b7db2ece8b9ca5d545d4a6c (patch)
tree04770c540ba8145f9288bad14ac5d4d59ac30c95 /sys/amd64/amd64/apic_vector.S
parent748f95c68727abdadaf3ea8816cc19784d05411d (diff)
downloadFreeBSD-src-a2b5da0090b331918b7db2ece8b9ca5d545d4a6c.zip
FreeBSD-src-a2b5da0090b331918b7db2ece8b9ca5d545d4a6c.tar.gz
Implement support for the process-context identifiers ('PCID') on
Intel CPUs. The feature tags TLB entries with the Id of the address space and allows to avoid TLB invalidation on the context switch, it is available only in the long mode. In the microbenchmarks, using the PCID decreased latency of the context switches by ~30% on SandyBridge class desktop CPUs, measured with the lat_ctx program from lmbench. If available, use INVPCID instruction when a TLB entry in non-current address space needs to be invalidated. The instruction is typically available on the Haswell. If needed, the use of PCID can be turned off with the vm.pmap.pcid_enabled loader tunable set to 0. The state of the feature is reported by the vm.pmap.pcid_enabled sysctl. The sysctl vm.pmap.pcid_save_cnt reports the number of context switches which avoided invalidating the TLB; compare with the total number of context switches, available as sysctl vm.stats.sys.v_swtch. Sponsored by: The FreeBSD Foundation Reviewed by: alc Tested by: pho, bf
Diffstat (limited to 'sys/amd64/amd64/apic_vector.S')
-rw-r--r--sys/amd64/amd64/apic_vector.S241
1 files changed, 193 insertions, 48 deletions
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 7551cc5..e868cf5 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -43,6 +43,12 @@
#include "assym.s"
+#ifdef SMP
+#define LK lock ;
+#else
+#define LK
+#endif
+
/*
* I/O Interrupt Entry Point. Rather than having one entry point for
* each interrupt source, we use one entry point for each 32-bit word
@@ -149,6 +155,38 @@ IDTVEC(xen_intr_upcall)
* Global address space TLB shootdown.
*/
.text
+
+#define NAKE_INTR_CS 24
+
+ SUPERALIGN_TEXT
+global_invltlb:
+ movl %cr4,%eax
+ andl $~0x80,%eax
+ movl %eax,%cr4
+ orl $0x80,%eax
+ movl %eax,%cr4
+invltlb_ret_clear_pm_save:
+ movq smp_tlb_pmap,%rdx
+ testq %rdx,%rdx
+ jz invltlb_ret
+ testb $SEL_RPL_MASK,NAKE_INTR_CS(%rsp)
+ jz 1f
+ swapgs
+1:
+ movl PCPU(CPUID),%eax
+ jz 2f
+ swapgs
+2:
+ LK btcl %eax,PM_SAVE(%rdx)
+ SUPERALIGN_TEXT
+invltlb_ret:
+ movq lapic, %rax
+ movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
+ LK incl smp_tlb_wait
+ popq %rdx
+ popq %rax
+ jmp doreti_iret
+
SUPERALIGN_TEXT
IDTVEC(invltlb)
#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
@@ -165,18 +203,44 @@ IDTVEC(invltlb)
#endif
pushq %rax
+ pushq %rdx
- movq %cr3, %rax /* invalidate the TLB */
- movq %rax, %cr3
-
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
-
- lock
- incl smp_tlb_wait
-
- popq %rax
- jmp doreti_iret
+ movq %cr3,%rax
+ cmpl $0,pmap_pcid_enabled
+ je 2f
+
+ movq $smp_tlb_invpcid,%rdx
+ cmpl $0,(%rdx)
+ je global_invltlb
+ cmpl $-1,(%rdx)
+ je global_invltlb
+
+ /*
+ * Non-zero smp_tlb_invpcid, only invalidate TLB for entries with
+ * current PCID.
+ */
+ cmpl $0,invpcid_works
+ je 1f
+ /* Use invpcid if available. */
+ movl $1,%eax /* INVPCID_CTX */
+ /* invpcid (%rdx),%rax */
+ .byte 0x66,0x0f,0x38,0x82,0x02
+ jmp invltlb_ret_clear_pm_save
+1:
+ /* Otherwise reload %cr3 twice. */
+ movq pcid_cr3,%rdx
+ cmpq %rax,%rdx
+ je 2f
+ movq %rdx,%cr3 /* Invalidate, bit 63 is zero. */
+ btsq $63,%rax
+
+ /*
+ * Invalidate the TLB if PCID is not enabled.
+ * Restore the old address space.
+ */
+2:
+ movq %rax,%cr3
+ jmp invltlb_ret_clear_pm_save
/*
* Single page TLB shootdown
@@ -198,18 +262,54 @@ IDTVEC(invlpg)
#endif
pushq %rax
-
- movq smp_tlb_addr1, %rax
- invlpg (%rax) /* invalidate single page */
-
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
-
- lock
- incl smp_tlb_wait
-
- popq %rax
- jmp doreti_iret
+ pushq %rdx
+ movq $smp_tlb_invpcid,%rdx
+ cmpl $0,pmap_pcid_enabled
+ je 3f
+ cmpl $0,invpcid_works
+ jne 2f
+
+ /* kernel pmap - use invlpg to invalidate global mapping */
+ cmpl $0,(%rdx)
+ je 3f
+ cmpl $-1,(%rdx)
+ je global_invltlb
+
+ /*
+ * PCID supported, but INVPCID is not.
+ * Temporarily switch to the target address space and do INVLPG.
+ */
+ pushq %rcx
+ movq %cr3,%rcx
+ movq pcid_cr3,%rax
+ cmp %rcx,%rax
+ je 1f
+ btsq $63,%rax
+ movq %rax,%cr3
+1: movq 8(%rdx),%rax
+ invlpg (%rax)
+ btsq $63,%rcx
+ movq %rcx,%cr3
+ popq %rcx
+ jmp invltlb_ret
+
+ /*
+ * Invalidate the TLB entry using INVPCID_ADDR.
+ */
+2:
+ xorl %eax,%eax
+/* invpcid (%rdx),%rax */
+ .byte 0x66,0x0f,0x38,0x82,0x02
+ jmp invltlb_ret
+
+ /*
+ * PCID is not supported or kernel pmap.
+ * Invalidate single page using INVLPG.
+ */
+3:
+ movq 8(%rdx),%rax
+ invlpg (%rax)
+ jmp invltlb_ret
/*
* Page range TLB shootdown.
@@ -232,23 +332,76 @@ IDTVEC(invlrng)
pushq %rax
pushq %rdx
-
- movq smp_tlb_addr1, %rdx
- movq smp_tlb_addr2, %rax
+ movq $smp_tlb_invpcid,%rdx
+ cmpl $0,pmap_pcid_enabled
+ jne invlrng_single_page
+ cmpl $0,invpcid_works
+ jne invlrng_invpcid
+
+ /* kernel pmap - use invlpg to invalidate global mapping */
+ cmpl $0,(%rdx)
+ je invlrng_single_page
+ cmpl $-1,(%rdx)
+ je global_invltlb
+
+ pushq %rcx
+ movq %cr3,%rcx
+ movq pcid_cr3,%rax
+ cmpq %rcx,%rax
+ je 1f
+ btsq $63,%rax
+ movq %rax,%cr3
+1:
+ movq 8(%rdx),%rdx
+ movq smp_tlb_addr2,%rax
+2:
+ invlpg (%rdx)
+ addq $PAGE_SIZE,%rdx
+ cmpq %rax,%rdx
+ jb 2b
+ btsq $63,%rcx
+ movq %rcx,%cr3
+ popq %rcx
+ jmp invltlb_ret
+
+invlrng_invpcid:
+ testb $SEL_RPL_MASK,NAKE_INTR_CS(%rsp)
+ jz 1f
+ swapgs
+1:
+ pushq %rcx
+ movq (%rdx),%rcx
+ movq %rcx,PCPU(INVPCID_DESCR)
+ movq 8(%rdx),%rax
+ movq %rax,PCPU(INVPCID_DESCR)+8
+ movq smp_tlb_addr2,%rcx
+ xorl %eax,%eax
+ movq $PC_INVPCID_DESCR,%rdx
+ gs
+ subq 8(%rdx),%rcx
+ shrq $PAGE_SHIFT,%rcx
+2:
+ gs
+// invpcid (%rdx),%rax
+ .byte 0x66,0x0f,0x38,0x82,0x02
+ gs
+ addq $PAGE_SIZE,8(%rdx)
+ dec %rcx
+ jne 2b
+ popq %rcx
+ testb $SEL_RPL_MASK,NAKE_INTR_CS(%rsp)
+ jz invltlb_ret
+ swapgs
+ jmp invltlb_ret
+
+invlrng_single_page:
+ movq 8(%rdx),%rdx
+ movq smp_tlb_addr2,%rax
1: invlpg (%rdx) /* invalidate single page */
- addq $PAGE_SIZE, %rdx
- cmpq %rax, %rdx
+ addq $PAGE_SIZE,%rdx
+ cmpq %rax,%rdx
jb 1b
-
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
-
- lock
- incl smp_tlb_wait
-
- popq %rdx
- popq %rax
- jmp doreti_iret
+ jmp invltlb_ret
/*
* Invalidate cache.
@@ -265,17 +418,9 @@ IDTVEC(invlcache)
#endif
pushq %rax
-
+ pushq %rdx
wbinvd
-
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
-
- lock
- incl smp_tlb_wait
-
- popq %rax
- jmp doreti_iret
+ jmp invltlb_ret
/*
* Handler for IPIs sent via the per-cpu IPI bitmap.
OpenPOWER on IntegriCloud