Skip to content

Commit 2e6bf0d

Browse files
committed
Inital stub for multi-threading support.
1 parent e28fcde commit 2e6bf0d

File tree

2 files changed

+169
-1
lines changed

2 files changed

+169
-1
lines changed

kernel/src/arch/x86_64/gdb/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use super::debug::GDB_REMOTE_PORT;
2222
use crate::error::KError;
2323

2424
mod breakpoints;
25+
mod multi_thread_ops;
2526
mod section_offsets;
2627
mod serial;
2728
mod single_register;
@@ -363,7 +364,11 @@ impl Target for KernelDebugger {
363364
type Arch = X86_64_SSE;
364365

365366
fn base_ops(&mut self) -> BaseOps<Self::Arch, Self::Error> {
366-
BaseOps::SingleThread(self)
367+
if cfg!(feature = "bsp-only") {
368+
BaseOps::SingleThread(self)
369+
} else {
370+
BaseOps::MultiThread(self)
371+
}
367372
}
368373

369374
fn support_section_offsets(&mut self) -> Option<SectionOffsetsOps<Self>> {
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#![allow(warnings)]
2+
3+
use core::convert::TryInto;
4+
5+
use log::{debug, error, info, trace, warn};
6+
7+
use gdbstub::common::{Signal, Tid};
8+
use gdbstub::target;
9+
use gdbstub::target::ext::base::multithread::{MultiThreadOps, MultiThreadSingleStep};
10+
use gdbstub::target::ext::breakpoints::WatchKind;
11+
use gdbstub::target::{Target, TargetError, TargetResult};
12+
13+
use super::{ExecMode, KernelDebugger};
14+
use crate::error::KError;
15+
use crate::memory::vspace::AddressSpace;
16+
use crate::memory::{VAddr, BASE_PAGE_SIZE};
17+
18+
impl MultiThreadOps for KernelDebugger {
19+
fn resume(&mut self) -> Result<(), Self::Error> {
20+
// Upon returning from the `resume` method, the target being debugged should be
21+
// configured to run according to whatever resume actions the GDB client has
22+
// specified (as specified by `set_resume_action`, `set_resume_range_step`,
23+
// `set_reverse_{step, continue}`, etc...)
24+
//
25+
// In this basic `armv4t_multicore` example, the `resume` method is actually a
26+
// no-op, as the execution mode of the emulator's interpreter loop has already
27+
// been modified via the various `set_X` methods.
28+
//
29+
// In more complex implementations, it's likely that the target being debugged
30+
// will be running in another thread / process, and will require some kind of
31+
// external "orchestration" to set it's execution mode (e.g: modifying the
32+
// target's process state via platform specific debugging syscalls).
33+
34+
Ok(())
35+
}
36+
37+
fn clear_resume_actions(&mut self) -> Result<(), Self::Error> {
38+
//self.exec_mode.clear();
39+
Ok(())
40+
}
41+
42+
#[inline(always)]
43+
fn support_single_step(
44+
&mut self,
45+
) -> Option<target::ext::base::multithread::MultiThreadSingleStepOps<Self>> {
46+
Some(self)
47+
}
48+
49+
fn set_resume_action_continue(
50+
&mut self,
51+
tid: Tid,
52+
signal: Option<Signal>,
53+
) -> Result<(), Self::Error> {
54+
/*if signal.is_some() {
55+
return Err(KError::Unknown);
56+
}
57+
58+
self.exec_mode
59+
.insert(tid_to_cpuid(tid)?, ExecMode::Continue);*/
60+
61+
Ok(())
62+
}
63+
64+
fn read_registers(
65+
&mut self,
66+
regs: &mut gdbstub_arch::x86::reg::X86_64CoreRegs,
67+
tid: Tid,
68+
) -> TargetResult<(), Self> {
69+
/*
70+
let cpu = match tid_to_cpuid(tid).map_err(TargetError::Fatal)? {
71+
CpuId::Cpu => &mut self.cpu,
72+
CpuId::Cop => &mut self.cop,
73+
};
74+
75+
let mode = cpu.mode();
76+
77+
for i in 0..13 {
78+
regs.r[i] = cpu.reg_get(mode, i as u8);
79+
}
80+
regs.sp = cpu.reg_get(mode, reg::SP);
81+
regs.lr = cpu.reg_get(mode, reg::LR);
82+
regs.pc = cpu.reg_get(mode, reg::PC);
83+
regs.cpsr = cpu.reg_get(mode, reg::CPSR);*/
84+
85+
Ok(())
86+
}
87+
88+
fn write_registers(
89+
&mut self,
90+
regs: &gdbstub_arch::x86::reg::X86_64CoreRegs,
91+
tid: Tid,
92+
) -> TargetResult<(), Self> {
93+
/*let cpu = match tid_to_cpuid(tid).map_err(TargetError::Fatal)? {
94+
CpuId::Cpu => &mut self.cpu,
95+
CpuId::Cop => &mut self.cop,
96+
};
97+
98+
let mode = cpu.mode();
99+
100+
for i in 0..13 {
101+
cpu.reg_set(mode, i, regs.r[i as usize]);
102+
}
103+
cpu.reg_set(mode, reg::SP, regs.sp);
104+
cpu.reg_set(mode, reg::LR, regs.lr);
105+
cpu.reg_set(mode, reg::PC, regs.pc);
106+
cpu.reg_set(mode, reg::CPSR, regs.cpsr);
107+
*/
108+
Ok(())
109+
}
110+
111+
fn read_addrs(
112+
&mut self,
113+
start_addr: u64,
114+
data: &mut [u8],
115+
_tid: Tid, // same address space for each core
116+
) -> TargetResult<(), Self> {
117+
/*for (addr, val) in (start_addr..).zip(data.iter_mut()) {
118+
*val = self.mem.r8(addr)
119+
}*/
120+
Ok(())
121+
}
122+
123+
fn write_addrs(
124+
&mut self,
125+
start_addr: u64,
126+
data: &[u8],
127+
_tid: Tid, // same address space for each core
128+
) -> TargetResult<(), Self> {
129+
/*for (addr, val) in (start_addr..).zip(data.iter().copied()) {
130+
self.mem.w8(addr, val)
131+
}*/
132+
Ok(())
133+
}
134+
135+
fn list_active_threads(
136+
&mut self,
137+
register_thread: &mut dyn FnMut(Tid),
138+
) -> Result<(), Self::Error> {
139+
//register_thread(cpuid_to_tid(CpuId::Cpu));
140+
//register_thread(cpuid_to_tid(CpuId::Cop));
141+
Ok(())
142+
}
143+
}
144+
145+
/// Adds `gdbstub` support for single-stepping.
146+
impl MultiThreadSingleStep for KernelDebugger {
147+
fn set_resume_action_step(
148+
&mut self,
149+
_tid: Tid,
150+
signal: Option<Signal>,
151+
) -> Result<(), Self::Error> {
152+
assert!(signal.is_none(), "Not supported at the moment.");
153+
154+
self._signal = signal;
155+
self.resume_with = Some(ExecMode::SingleStep);
156+
info!(
157+
"SingleThreadSingleStep::step: set signal = {:?} resume_with = {:?}",
158+
signal, self.resume_with
159+
);
160+
161+
Ok(())
162+
}
163+
}

0 commit comments

Comments
 (0)