diff options
author | Itamar <itamar8910@gmail.com> | 2020-04-13 16:37:47 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-13 23:20:59 +0200 |
commit | d04409b44418f80fa21c542fb9b80f3adc13542d (patch) | |
tree | 6afe733e2753d397d94b2e627ad493f87df763d0 /Kernel/Arch | |
parent | 1191ab9500520b512e2074fe0244b38d8ddc424d (diff) | |
download | serenity-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.cpp | 33 | ||||
-rw-r--r-- | Kernel/Arch/i386/CPU.h | 2 |
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" |