mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 19:27:45 +00:00
Kernel: Add debug register handling
This patch adds functions to read/write from the debug registers, and implements storing/loading them across context switches.
This commit is contained in:
parent
c84107a1ab
commit
97a4c627cb
3 changed files with 97 additions and 11 deletions
|
@ -855,19 +855,70 @@ FlatPtr read_cr4()
|
||||||
return cr4;
|
return cr4;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatPtr read_dr6()
|
void read_debug_registers_into(DebugRegisterState& state)
|
||||||
{
|
{
|
||||||
FlatPtr dr6;
|
state.dr0 = read_dr0();
|
||||||
#if ARCH(I386)
|
state.dr1 = read_dr1();
|
||||||
asm("mov %%dr6, %%eax"
|
state.dr2 = read_dr2();
|
||||||
: "=a"(dr6));
|
state.dr3 = read_dr3();
|
||||||
#else
|
state.dr6 = read_dr6();
|
||||||
asm("mov %%dr6, %%rax"
|
state.dr7 = read_dr7();
|
||||||
: "=a"(dr6));
|
|
||||||
#endif
|
|
||||||
return dr6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_debug_registers_from(const DebugRegisterState& state)
|
||||||
|
{
|
||||||
|
write_dr0(state.dr0);
|
||||||
|
write_dr1(state.dr1);
|
||||||
|
write_dr2(state.dr2);
|
||||||
|
write_dr3(state.dr3);
|
||||||
|
write_dr6(state.dr6);
|
||||||
|
write_dr7(state.dr7);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_debug_registers()
|
||||||
|
{
|
||||||
|
write_dr0(0);
|
||||||
|
write_dr1(0);
|
||||||
|
write_dr2(0);
|
||||||
|
write_dr3(0);
|
||||||
|
write_dr7(1 << 10); // Bit 10 is reserved and must be set to 1.
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARCH(I386)
|
||||||
|
# define DEFINE_DEBUG_REGISTER(index) \
|
||||||
|
FlatPtr read_dr##index() \
|
||||||
|
{ \
|
||||||
|
FlatPtr value; \
|
||||||
|
asm("mov %%dr" #index ", %%eax" \
|
||||||
|
: "=a"(value)); \
|
||||||
|
return value; \
|
||||||
|
} \
|
||||||
|
void write_dr##index(FlatPtr value) \
|
||||||
|
{ \
|
||||||
|
asm volatile("mov %%eax, %%dr" #index ::"a"(value)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define DEFINE_DEBUG_REGISTER(index) \
|
||||||
|
FlatPtr read_dr##index() \
|
||||||
|
{ \
|
||||||
|
FlatPtr value; \
|
||||||
|
asm("mov %%dr" #index ", %%rax" \
|
||||||
|
: "=a"(value)); \
|
||||||
|
return value; \
|
||||||
|
} \
|
||||||
|
void write_dr##index(FlatPtr value) \
|
||||||
|
{ \
|
||||||
|
asm volatile("mov %%rax, %%dr" #index ::"a"(value)); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEBUG_REGISTER(0);
|
||||||
|
DEFINE_DEBUG_REGISTER(1);
|
||||||
|
DEFINE_DEBUG_REGISTER(2);
|
||||||
|
DEFINE_DEBUG_REGISTER(3);
|
||||||
|
DEFINE_DEBUG_REGISTER(6);
|
||||||
|
DEFINE_DEBUG_REGISTER(7);
|
||||||
|
|
||||||
#define XCR_XFEATURE_ENABLED_MASK 0
|
#define XCR_XFEATURE_ENABLED_MASK 0
|
||||||
|
|
||||||
UNMAP_AFTER_INIT u64 read_xcr0()
|
UNMAP_AFTER_INIT u64 read_xcr0()
|
||||||
|
@ -1391,6 +1442,15 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread)
|
||||||
set_fs(to_tss.fs);
|
set_fs(to_tss.fs);
|
||||||
set_gs(to_tss.gs);
|
set_gs(to_tss.gs);
|
||||||
|
|
||||||
|
if (from_thread->process().is_traced())
|
||||||
|
read_debug_registers_into(from_thread->debug_register_state());
|
||||||
|
|
||||||
|
if (to_thread->process().is_traced()) {
|
||||||
|
write_debug_registers_from(to_thread->debug_register_state());
|
||||||
|
} else {
|
||||||
|
clear_debug_registers();
|
||||||
|
}
|
||||||
|
|
||||||
auto& processor = Processor::current();
|
auto& processor = Processor::current();
|
||||||
auto& tls_descriptor = processor.get_gdt_entry(GDT_SELECTOR_TLS);
|
auto& tls_descriptor = processor.get_gdt_entry(GDT_SELECTOR_TLS);
|
||||||
tls_descriptor.set_base(to_thread->thread_specific_data());
|
tls_descriptor.set_base(to_thread->thread_specific_data());
|
||||||
|
@ -1404,7 +1464,6 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread)
|
||||||
|
|
||||||
asm volatile("fxrstor %0" ::"m"(to_thread->fpu_state()));
|
asm volatile("fxrstor %0" ::"m"(to_thread->fpu_state()));
|
||||||
|
|
||||||
// TODO: debug registers
|
|
||||||
// TODO: ioperm?
|
// TODO: ioperm?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -430,6 +430,15 @@ struct [[gnu::packed]] RegisterState {
|
||||||
FlatPtr userspace_ss;
|
FlatPtr userspace_ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct [[gnu::packed]] DebugRegisterState {
|
||||||
|
FlatPtr dr0;
|
||||||
|
FlatPtr dr1;
|
||||||
|
FlatPtr dr2;
|
||||||
|
FlatPtr dr3;
|
||||||
|
FlatPtr dr6;
|
||||||
|
FlatPtr dr7;
|
||||||
|
};
|
||||||
|
|
||||||
#if ARCH(I386)
|
#if ARCH(I386)
|
||||||
# define REGISTER_STATE_SIZE (19 * 4)
|
# define REGISTER_STATE_SIZE (19 * 4)
|
||||||
#else
|
#else
|
||||||
|
@ -476,7 +485,21 @@ void write_cr3(FlatPtr);
|
||||||
void write_cr4(FlatPtr);
|
void write_cr4(FlatPtr);
|
||||||
void write_xcr0(u64);
|
void write_xcr0(u64);
|
||||||
|
|
||||||
|
void read_debug_registers_into(DebugRegisterState&);
|
||||||
|
void write_debug_registers_from(const DebugRegisterState&);
|
||||||
|
void clear_debug_registers();
|
||||||
|
FlatPtr read_dr0();
|
||||||
|
void write_dr0(FlatPtr);
|
||||||
|
FlatPtr read_dr1();
|
||||||
|
void write_dr1(FlatPtr);
|
||||||
|
FlatPtr read_dr2();
|
||||||
|
void write_dr2(FlatPtr);
|
||||||
|
FlatPtr read_dr3();
|
||||||
|
void write_dr3(FlatPtr);
|
||||||
FlatPtr read_dr6();
|
FlatPtr read_dr6();
|
||||||
|
void write_dr6(FlatPtr);
|
||||||
|
FlatPtr read_dr7();
|
||||||
|
void write_dr7(FlatPtr);
|
||||||
|
|
||||||
static inline bool is_kernel_mode()
|
static inline bool is_kernel_mode()
|
||||||
{
|
{
|
||||||
|
|
|
@ -763,6 +763,9 @@ public:
|
||||||
RegisterState& get_register_dump_from_stack();
|
RegisterState& get_register_dump_from_stack();
|
||||||
const RegisterState& get_register_dump_from_stack() const { return const_cast<Thread*>(this)->get_register_dump_from_stack(); }
|
const RegisterState& get_register_dump_from_stack() const { return const_cast<Thread*>(this)->get_register_dump_from_stack(); }
|
||||||
|
|
||||||
|
DebugRegisterState& debug_register_state() { return m_debug_register_state; }
|
||||||
|
const DebugRegisterState& debug_register_state() const { return m_debug_register_state; }
|
||||||
|
|
||||||
TSS& tss() { return m_tss; }
|
TSS& tss() { return m_tss; }
|
||||||
const TSS& tss() const { return m_tss; }
|
const TSS& tss() const { return m_tss; }
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
|
@ -1200,6 +1203,7 @@ private:
|
||||||
NonnullRefPtr<Process> m_process;
|
NonnullRefPtr<Process> m_process;
|
||||||
ThreadID m_tid { -1 };
|
ThreadID m_tid { -1 };
|
||||||
TSS m_tss {};
|
TSS m_tss {};
|
||||||
|
DebugRegisterState m_debug_register_state {};
|
||||||
TrapFrame* m_current_trap { nullptr };
|
TrapFrame* m_current_trap { nullptr };
|
||||||
u32 m_saved_critical { 1 };
|
u32 m_saved_critical { 1 };
|
||||||
IntrusiveListNode<Thread> m_ready_queue_node;
|
IntrusiveListNode<Thread> m_ready_queue_node;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue