x86/cpu: Implement CPU vulnerabilites sysfs functions
[pandora-kernel.git] / arch / x86 / kernel / kgdb.c
index faba577..2f45c4c 100644 (file)
@@ -43,6 +43,8 @@
 #include <linux/smp.h>
 #include <linux/nmi.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/uaccess.h>
+#include <linux/memory.h>
 
 #include <asm/debugreg.h>
 #include <asm/apicdef.h>
@@ -740,6 +742,64 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
        regs->ip = ip;
 }
 
+int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
+{
+       int err;
+       char opc[BREAK_INSTR_SIZE];
+
+       bpt->type = BP_BREAKPOINT;
+       err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
+                               BREAK_INSTR_SIZE);
+       if (err)
+               return err;
+       err = probe_kernel_write((char *)bpt->bpt_addr,
+                                arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+#ifdef CONFIG_DEBUG_RODATA
+       if (!err)
+               return err;
+       /*
+        * It is safe to call text_poke() because normal kernel execution
+        * is stopped on all cores, so long as the text_mutex is not locked.
+        */
+       if (mutex_is_locked(&text_mutex))
+               return -EBUSY;
+       text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr,
+                 BREAK_INSTR_SIZE);
+       err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
+       if (err)
+               return err;
+       if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE))
+               return -EINVAL;
+       bpt->type = BP_POKE_BREAKPOINT;
+#endif /* CONFIG_DEBUG_RODATA */
+       return err;
+}
+
+int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
+{
+#ifdef CONFIG_DEBUG_RODATA
+       int err;
+       char opc[BREAK_INSTR_SIZE];
+
+       if (bpt->type != BP_POKE_BREAKPOINT)
+               goto knl_write;
+       /*
+        * It is safe to call text_poke() because normal kernel execution
+        * is stopped on all cores, so long as the text_mutex is not locked.
+        */
+       if (mutex_is_locked(&text_mutex))
+               goto knl_write;
+       text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE);
+       err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
+       if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE))
+               goto knl_write;
+       return err;
+knl_write:
+#endif /* CONFIG_DEBUG_RODATA */
+       return probe_kernel_write((char *)bpt->bpt_addr,
+                                 (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
+}
+
 struct kgdb_arch arch_kgdb_ops = {
        /* Breakpoint instruction: */
        .gdb_bpt_instr          = { 0xcc },