x86: mtrr: Abort if requested size is not power of 2
authorBin Meng <bmeng.cn@gmail.com>
Sat, 31 Jul 2021 08:45:26 +0000 (16:45 +0800)
committerBin Meng <bmeng.cn@gmail.com>
Mon, 2 Aug 2021 07:11:41 +0000 (15:11 +0800)
The size parameter of mtrr_add_request() and mtrr_set_next_var()
shall be power of 2, otherwise the logic creates a mask that does
not meet the requirement of IA32_MTRR_PHYSMASK register.

Programming such a mask value to IA32_MTRR_PHYSMASK generates #GP.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested on chromebook_coral, chromebook_samus, chromebook_link, minnowmax
Tested-by: Simon Glass <sjg@chromium.org>
arch/x86/cpu/mtrr.c
arch/x86/include/asm/mtrr.h

index 14c644e..260a008 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/mp.h>
 #include <asm/msr.h>
 #include <asm/mtrr.h>
+#include <linux/log2.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -179,6 +180,9 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
        if (!gd->arch.has_mtrr)
                return -ENOSYS;
 
+       if (!is_power_of_2(size))
+               return -EINVAL;
+
        if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
                return -ENOSPC;
        req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
@@ -223,6 +227,9 @@ int mtrr_set_next_var(uint type, uint64_t start, uint64_t size)
 {
        int mtrr;
 
+       if (!is_power_of_2(size))
+               return -EINVAL;
+
        mtrr = get_free_var_mtrr();
        if (mtrr < 0)
                return mtrr;
index 384672e..d1aa86b 100644 (file)
@@ -119,7 +119,7 @@ void mtrr_close(struct mtrr_state *state, bool do_caches);
  *
  * @type:      Requested type (MTRR_TYPE_)
  * @start:     Start address
- * @size:      Size
+ * @size:      Size, must be power of 2
  *
  * @return:    0 on success, non-zero on failure
  */
@@ -144,8 +144,9 @@ int mtrr_commit(bool do_caches);
  *
  * @type:      Requested type (MTRR_TYPE_)
  * @start:     Start address
- * @size:      Size
- * @return 0 on success, -ENOSPC if there are no more MTRRs
+ * @size:      Size, must be power of 2
+ * @return 0 on success, -EINVAL if size is not power of 2,
+ * -ENOSPC if there are no more MTRRs
  */
 int mtrr_set_next_var(uint type, uint64_t base, uint64_t size);