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