x86, mtrr: Use explicit sizing and padding for the 64-bit ioctls
authorH. Peter Anvin <hpa@linux.intel.com>
Mon, 27 Feb 2012 23:15:25 +0000 (15:15 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 1 Mar 2012 20:48:52 +0000 (12:48 -0800)
Specify the data structures for the 64-bit ioctls with explicit sizing
and padding so that the x32 kernel will correctly use the 64-bit forms
of these ioctls.  Note that these ioctls are bogus in both forms on
both 32 and 64 bits; even on 64 bits the maximum MTRR size is only 44
bits long.

Note that nothing really is supposed to use these ioctls and that the
preferred interface is text strings on /proc/mtrr, or better yet,
nothing at all (use /sys/bus/pci/devices/*/resource*_wc for write
combining; that uses PAT not MTRRs.)

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: H. J. Lu <hjl.tools@gmail.com>
Tested-by: Nitin A. Kamble <nitin.a.kamble@intel.com>
Link: http://lkml.kernel.org/n/tip-vwvnlu3hjmtkwvij4qxtm90l@git.kernel.org
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/mtrr.h
arch/x86/kernel/cpu/mtrr/if.c

index 4365ffdb461f52b946b8e71c5ffa6c250d7f12be..7e3f17f92c665ec79850eefa328567e06c50134c 100644 (file)
 
 #define        MTRR_IOCTL_BASE 'M'
 
-struct mtrr_sentry {
-    unsigned long base;    /*  Base address     */
-    unsigned int size;    /*  Size of region   */
-    unsigned int type;     /*  Type of region   */
-};
-
 /* Warning: this structure has a different order from i386
    on x86-64. The 32bit emulation code takes care of that.
    But you need to use this for 64bit, otherwise your X server
    will break. */
 
 #ifdef __i386__
+struct mtrr_sentry {
+    unsigned long base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
 struct mtrr_gentry {
     unsigned int regnum;   /*  Register number  */
     unsigned long base;    /*  Base address     */
@@ -50,12 +50,20 @@ struct mtrr_gentry {
 
 #else /* __i386__ */
 
+struct mtrr_sentry {
+       __u64 base;             /*  Base address     */
+       __u32 size;             /*  Size of region   */
+       __u32 type;             /*  Type of region   */
+};
+
 struct mtrr_gentry {
-    unsigned long base;    /*  Base address     */
-    unsigned int size;    /*  Size of region   */
-    unsigned int regnum;   /*  Register number  */
-    unsigned int type;     /*  Type of region   */
+       __u64 base;             /*  Base address     */
+       __u32 size;             /*  Size of region   */
+       __u32 regnum;           /*  Register number  */
+       __u32 type;             /*  Type of region   */
+       __u32 _pad;             /*  Unused           */
 };
+
 #endif /* !__i386__ */
 
 struct mtrr_var_range {
index 79289632cb270cb4aa02c1e5cc58d4c3de5b53b1..a041e094b8b9fd68a520d5952c8ed05a4bdd7380 100644 (file)
@@ -167,6 +167,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
 {
        int err = 0;
        mtrr_type type;
+       unsigned long base;
        unsigned long size;
        struct mtrr_sentry sentry;
        struct mtrr_gentry gentry;
@@ -267,14 +268,14 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
 #endif
                if (gentry.regnum >= num_var_ranges)
                        return -EINVAL;
-               mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
+               mtrr_if->get(gentry.regnum, &base, &size, &type);
 
                /* Hide entries that go above 4GB */
-               if (gentry.base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
+               if (base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
                    || size >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT)))
                        gentry.base = gentry.size = gentry.type = 0;
                else {
-                       gentry.base <<= PAGE_SHIFT;
+                       gentry.base = base << PAGE_SHIFT;
                        gentry.size = size << PAGE_SHIFT;
                        gentry.type = type;
                }
@@ -321,11 +322,12 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
 #endif
                if (gentry.regnum >= num_var_ranges)
                        return -EINVAL;
-               mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
+               mtrr_if->get(gentry.regnum, &base, &size, &type);
                /* Hide entries that would overflow */
                if (size != (__typeof__(gentry.size))size)
                        gentry.base = gentry.size = gentry.type = 0;
                else {
+                       gentry.base = base;
                        gentry.size = size;
                        gentry.type = type;
                }