The Intel SDM says (Volume 3, 7.2.1):

   Avoid placing a page boundary in the part of the TSS that the
   processor reads during a task switch (the first 104 bytes). The
   processor may not correctly perform address translations if a
   boundary occurs in this area. During a task switch, the processor
   reads and writes into the first 104 bytes of each TSS (using
   contiguous physical addresses beginning with the physical address
   of the first byte of the TSS). So, after TSS access begins, if
   part of the 104 bytes is not physically contiguous, the processor
   will access incorrect information without generating a page-fault
   exception.

Merely cacheline-aligning the TSS doesn't actually guarantee that
the hardware TSS doesn't span a page.  Instead, page-align the
structure that contains it.

Signed-off-by: Andy Lutomirski <l...@kernel.org>
---
 arch/x86/include/asm/processor.h | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 301d41ca1fa1..97ded6e3edd3 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -326,6 +326,16 @@ struct x86_hw_tss {
 
 struct tss_struct {
        /*
+        * Space for the temporary SYSENTER stack.  Used for the entry
+        * trampoline as well.  Size it such that tss_struct ends up
+        * as a multiple of PAGE_SIZE.  This calculation assumes that
+        * io_bitmap is a multiple of PAGE_SIZE (8192 bytes) plus one
+        * long.
+        */
+       unsigned long           SYSENTER_stack_canary;
+       unsigned long           SYSENTER_stack[(PAGE_SIZE - sizeof(struct 
x86_hw_tss)) / sizeof(unsigned long) - 2];
+
+       /*
         * The hardware state:
         */
        struct x86_hw_tss       x86_tss;
@@ -337,15 +347,9 @@ struct tss_struct {
         * be within the limit.
         */
        unsigned long           io_bitmap[IO_BITMAP_LONGS + 1];
-
-       /*
-        * Space for the temporary SYSENTER stack.
-        */
-       unsigned long           SYSENTER_stack_canary;
-       unsigned long           SYSENTER_stack[64];
 } ____cacheline_aligned;
 
-DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss);
+DECLARE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss);
 
 /*
  * sizeof(unsigned long) coming from an extra "long" at the end
-- 
2.13.6

Reply via email to