summaryrefslogtreecommitdiff
path: root/Kernel/Arch
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2020-04-13 16:37:47 +0300
committerAndreas Kling <kling@serenityos.org>2020-04-13 23:20:59 +0200
commitd04409b44418f80fa21c542fb9b80f3adc13542d (patch)
tree6afe733e2753d397d94b2e627ad493f87df763d0 /Kernel/Arch
parent1191ab9500520b512e2074fe0244b38d8ddc424d (diff)
downloadserenity-d04409b44418f80fa21c542fb9b80f3adc13542d.zip
CPU: Handle Debug exception
We currently only care about debug exceptions that are triggered by the single-step execution mode. The debug exception is translated to a SIGTRAP, which can be caught and handled by the tracing thread.
Diffstat (limited to 'Kernel/Arch')
-rw-r--r--Kernel/Arch/i386/CPU.cpp33
-rw-r--r--Kernel/Arch/i386/CPU.h2
2 files changed, 32 insertions, 3 deletions
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp
index 460cb47243..3e610b94ff 100644
--- a/Kernel/Arch/i386/CPU.cpp
+++ b/Kernel/Arch/i386/CPU.cpp
@@ -297,11 +297,31 @@ void page_fault_handler(RegisterState regs)
}
}
+EH_ENTRY_NO_CODE(1, debug);
+void debug_handler(RegisterState regs)
+{
+ clac();
+ if (!Process::current || (regs.cs & 3) == 0) {
+ klog() << "Debug Exception in Ring0";
+ hang();
+ return;
+ }
+ constexpr u8 REASON_SINGLESTEP = 14;
+ bool is_reason_singlestep = (read_dr6() & (1 << REASON_SINGLESTEP));
+ if (!is_reason_singlestep)
+ return;
+
+ if (Thread::current->tracer()) {
+ Thread::current->tracer()->set_regs(regs);
+ }
+ Thread::current->send_urgent_signal_to_self(SIGTRAP);
+}
+
EH_ENTRY_NO_CODE(3, breakpoint);
void breakpoint_handler(RegisterState regs)
{
clac();
- if (!Process::current || Process::current->is_ring0()) {
+ if (!Process::current || (regs.cs & 3) == 0) {
klog() << "Breakpoint Trap in Ring0";
hang();
return;
@@ -329,7 +349,6 @@ void breakpoint_handler(RegisterState regs)
hang(); \
}
-EH(1, "Debug exception")
EH(2, "Unknown error")
EH(4, "Overflow")
EH(5, "Bounds check")
@@ -498,7 +517,7 @@ void idt_init()
register_interrupt_handler(i, unimp_trap);
register_interrupt_handler(0x00, divide_error_asm_entry);
- register_interrupt_handler(0x01, _exception1);
+ register_user_callable_interrupt_handler(0x01, debug_asm_entry);
register_interrupt_handler(0x02, _exception2);
register_user_callable_interrupt_handler(0x03, breakpoint_asm_entry);
register_interrupt_handler(0x04, _exception4);
@@ -828,6 +847,14 @@ void write_cr3(u32 cr3)
: "memory");
}
+u32 read_dr6()
+{
+ u32 dr6;
+ asm("movl %%dr6, %%eax"
+ : "=a"(dr6));
+ return dr6;
+}
+
}
#ifdef DEBUG
diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h
index 87aebc3887..02f3162f8b 100644
--- a/Kernel/Arch/i386/CPU.h
+++ b/Kernel/Arch/i386/CPU.h
@@ -480,6 +480,8 @@ inline FlatPtr offset_in_page(const void* address)
u32 read_cr3();
void write_cr3(u32);
+u32 read_dr6();
+
class CPUID {
public:
CPUID(u32 function) { asm volatile("cpuid"