mce-inject.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * Machine check injection support.
  3. * Copyright 2008 Intel Corporation.
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; version 2
  8. * of the License.
  9. *
  10. * Authors:
  11. * Andi Kleen
  12. * Ying Huang
  13. */
  14. #include <linux/uaccess.h>
  15. #include <linux/module.h>
  16. #include <linux/timer.h>
  17. #include <linux/kernel.h>
  18. #include <linux/string.h>
  19. #include <linux/fs.h>
  20. #include <linux/smp.h>
  21. #include <asm/mce.h>
  22. /* Update fake mce registers on current CPU. */
  23. static void inject_mce(struct mce *m)
  24. {
  25. struct mce *i = &per_cpu(injectm, m->extcpu);
  26. /* Make sure noone reads partially written injectm */
  27. i->finished = 0;
  28. mb();
  29. m->finished = 0;
  30. /* First set the fields after finished */
  31. i->extcpu = m->extcpu;
  32. mb();
  33. /* Now write record in order, finished last (except above) */
  34. memcpy(i, m, sizeof(struct mce));
  35. /* Finally activate it */
  36. mb();
  37. i->finished = 1;
  38. }
  39. struct delayed_mce {
  40. struct timer_list timer;
  41. struct mce m;
  42. };
  43. /* Inject mce on current CPU */
  44. static void raise_mce(unsigned long data)
  45. {
  46. struct delayed_mce *dm = (struct delayed_mce *)data;
  47. struct mce *m = &dm->m;
  48. int cpu = m->extcpu;
  49. inject_mce(m);
  50. if (m->status & MCI_STATUS_UC) {
  51. struct pt_regs regs;
  52. memset(&regs, 0, sizeof(struct pt_regs));
  53. regs.ip = m->ip;
  54. regs.cs = m->cs;
  55. printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu);
  56. do_machine_check(&regs, 0);
  57. printk(KERN_INFO "MCE exception done on CPU %d\n", cpu);
  58. } else {
  59. mce_banks_t b;
  60. memset(&b, 0xff, sizeof(mce_banks_t));
  61. printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu);
  62. machine_check_poll(0, &b);
  63. mce_notify_irq();
  64. printk(KERN_INFO "Finished machine check poll on CPU %d\n",
  65. cpu);
  66. }
  67. kfree(dm);
  68. }
  69. /* Error injection interface */
  70. static ssize_t mce_write(struct file *filp, const char __user *ubuf,
  71. size_t usize, loff_t *off)
  72. {
  73. struct delayed_mce *dm;
  74. struct mce m;
  75. if (!capable(CAP_SYS_ADMIN))
  76. return -EPERM;
  77. /*
  78. * There are some cases where real MSR reads could slip
  79. * through.
  80. */
  81. if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
  82. return -EIO;
  83. if ((unsigned long)usize > sizeof(struct mce))
  84. usize = sizeof(struct mce);
  85. if (copy_from_user(&m, ubuf, usize))
  86. return -EFAULT;
  87. if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
  88. return -EINVAL;
  89. dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL);
  90. if (!dm)
  91. return -ENOMEM;
  92. /*
  93. * Need to give user space some time to set everything up,
  94. * so do it a jiffie or two later everywhere.
  95. * Should we use a hrtimer here for better synchronization?
  96. */
  97. memcpy(&dm->m, &m, sizeof(struct mce));
  98. setup_timer(&dm->timer, raise_mce, (unsigned long)dm);
  99. dm->timer.expires = jiffies + 2;
  100. add_timer_on(&dm->timer, m.extcpu);
  101. return usize;
  102. }
  103. static int inject_init(void)
  104. {
  105. printk(KERN_INFO "Machine check injector initialized\n");
  106. mce_chrdev_ops.write = mce_write;
  107. return 0;
  108. }
  109. module_init(inject_init);
  110. /*
  111. * Cannot tolerate unloading currently because we cannot
  112. * guarantee all openers of mce_chrdev will get a reference to us.
  113. */
  114. MODULE_LICENSE("GPL");