summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64/apic_vector.S
diff options
context:
space:
mode:
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