Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b263b31e authored by H. Peter Anvin's avatar H. Peter Anvin Committed by H. Peter Anvin
Browse files

x86, mtrr: Use explicit sizing and padding for the 64-bit ioctls



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: default avatarH. Peter Anvin <hpa@linux.intel.com>
Cc: H. J. Lu <hjl.tools@gmail.com>
Tested-by: default avatarNitin A. Kamble <nitin.a.kamble@intel.com>
Link: http://lkml.kernel.org/n/tip-vwvnlu3hjmtkwvij4qxtm90l@git.kernel.org


Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 8bd69c2d
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -29,18 +29,18 @@

#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 {
+6 −4
Original line number Diff line number Diff line
@@ -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;
		}