powerpc.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "lkdtm.h"
  3. #include <linux/slab.h>
  4. #include <linux/vmalloc.h>
  5. #include <asm/mmu.h>
  6. /* Inserts new slb entries */
  7. static void insert_slb_entry(unsigned long p, int ssize, int page_size)
  8. {
  9. unsigned long flags;
  10. flags = SLB_VSID_KERNEL | mmu_psize_defs[page_size].sllp;
  11. preempt_disable();
  12. asm volatile("slbmte %0,%1" :
  13. : "r" (mk_vsid_data(p, ssize, flags)),
  14. "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED))
  15. : "memory");
  16. asm volatile("slbmte %0,%1" :
  17. : "r" (mk_vsid_data(p, ssize, flags)),
  18. "r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED + 1))
  19. : "memory");
  20. preempt_enable();
  21. }
  22. /* Inject slb multihit on vmalloc-ed address i.e 0xD00... */
  23. static int inject_vmalloc_slb_multihit(void)
  24. {
  25. char *p;
  26. p = vmalloc(PAGE_SIZE);
  27. if (!p)
  28. return -ENOMEM;
  29. insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_vmalloc_psize);
  30. /*
  31. * This triggers exception, If handled correctly we must recover
  32. * from this error.
  33. */
  34. p[0] = '!';
  35. vfree(p);
  36. return 0;
  37. }
  38. /* Inject slb multihit on kmalloc-ed address i.e 0xC00... */
  39. static int inject_kmalloc_slb_multihit(void)
  40. {
  41. char *p;
  42. p = kmalloc(2048, GFP_KERNEL);
  43. if (!p)
  44. return -ENOMEM;
  45. insert_slb_entry((unsigned long)p, MMU_SEGSIZE_1T, mmu_linear_psize);
  46. /*
  47. * This triggers exception, If handled correctly we must recover
  48. * from this error.
  49. */
  50. p[0] = '!';
  51. kfree(p);
  52. return 0;
  53. }
  54. /*
  55. * Few initial SLB entries are bolted. Add a test to inject
  56. * multihit in bolted entry 0.
  57. */
  58. static void insert_dup_slb_entry_0(void)
  59. {
  60. unsigned long test_address = PAGE_OFFSET, *test_ptr;
  61. unsigned long esid, vsid;
  62. unsigned long i = 0;
  63. test_ptr = (unsigned long *)test_address;
  64. preempt_disable();
  65. asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
  66. asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
  67. /* for i !=0 we would need to mask out the old entry number */
  68. asm volatile("slbmte %0,%1" :
  69. : "r" (vsid),
  70. "r" (esid | SLB_NUM_BOLTED)
  71. : "memory");
  72. asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
  73. asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
  74. /* for i !=0 we would need to mask out the old entry number */
  75. asm volatile("slbmte %0,%1" :
  76. : "r" (vsid),
  77. "r" (esid | (SLB_NUM_BOLTED + 1))
  78. : "memory");
  79. pr_info("%s accessing test address 0x%lx: 0x%lx\n",
  80. __func__, test_address, *test_ptr);
  81. preempt_enable();
  82. }
  83. static void lkdtm_PPC_SLB_MULTIHIT(void)
  84. {
  85. if (!radix_enabled()) {
  86. pr_info("Injecting SLB multihit errors\n");
  87. /*
  88. * These need not be separate tests, And they do pretty
  89. * much same thing. In any case we must recover from the
  90. * errors introduced by these functions, machine would not
  91. * survive these tests in case of failure to handle.
  92. */
  93. inject_vmalloc_slb_multihit();
  94. inject_kmalloc_slb_multihit();
  95. insert_dup_slb_entry_0();
  96. pr_info("Recovered from SLB multihit errors\n");
  97. } else {
  98. pr_err("XFAIL: This test is for ppc64 and with hash mode MMU only\n");
  99. }
  100. }
  101. static struct crashtype crashtypes[] = {
  102. CRASHTYPE(PPC_SLB_MULTIHIT),
  103. };
  104. struct crashtype_category powerpc_crashtypes = {
  105. .crashtypes = crashtypes,
  106. .len = ARRAY_SIZE(crashtypes),
  107. };