Skip to content

Commit 5ca88b8

Browse files
committed
feat: 添加可选的 QEMU 配置 to_bin 覆盖选项,改进输出匹配器和 U-Boot 处理
1 parent fb8e4d8 commit 5ca88b8

5 files changed

Lines changed: 153 additions & 214 deletions

File tree

ostool/src/build/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub enum CargoRunnerKind {
5353
debug: bool,
5454
/// Whether to dump the device tree blob.
5555
dtb_dump: bool,
56+
/// Optional override for the generated QEMU config `to_bin` default.
57+
to_bin: Option<bool>,
5658
/// Extra default QEMU command-line arguments.
5759
args: Vec<String>,
5860
/// Regex patterns that indicate successful execution.
@@ -166,6 +168,7 @@ impl Tool {
166168
CargoRunnerKind::Qemu {
167169
qemu_config,
168170
dtb_dump,
171+
to_bin,
169172
args,
170173
success_regex,
171174
fail_regex,
@@ -184,6 +187,7 @@ impl Tool {
184187
dtb_dump: *dtb_dump,
185188
show_output: true,
186189
},
190+
*to_bin,
187191
args.clone(),
188192
success_regex.clone(),
189193
fail_regex.clone(),

ostool/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ async fn try_main() -> Result<()> {
120120
qemu_config: qemu_args.qemu_config,
121121
debug: qemu_args.debug,
122122
dtb_dump: qemu_args.dtb_dump,
123+
to_bin: None,
123124
args: vec![],
124125
success_regex: vec![],
125126
fail_regex: vec![],

ostool/src/run/output_matcher.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::time::{Duration, Instant};
22

33
use anyhow::anyhow;
4+
use colored::Colorize;
45
use regex::Regex;
56

67
pub(crate) const MATCH_DRAIN_DURATION: Duration = Duration::from_millis(500);
@@ -11,6 +12,19 @@ pub(crate) enum StreamMatchKind {
1112
Fail,
1213
}
1314

15+
impl StreamMatchKind {
16+
pub(crate) fn into_result(self, matched: &StreamMatch) -> anyhow::Result<()> {
17+
match self {
18+
StreamMatchKind::Success => Ok(()),
19+
StreamMatchKind::Fail => Err(anyhow!(
20+
"Fail pattern matched '{}': {}",
21+
matched.matched_regex,
22+
matched.matched_text.trim_end()
23+
)),
24+
}
25+
}
26+
}
27+
1428
#[derive(Debug, Clone)]
1529
pub(crate) struct StreamMatch {
1630
pub(crate) kind: StreamMatchKind,
@@ -19,6 +33,40 @@ pub(crate) struct StreamMatch {
1933
pub(crate) deadline: Instant,
2034
}
2135

36+
pub(crate) fn compile_regexes(
37+
success_patterns: &[String],
38+
fail_patterns: &[String],
39+
) -> anyhow::Result<(Vec<Regex>, Vec<Regex>)> {
40+
let success_regex = success_patterns
41+
.iter()
42+
.map(|p| Regex::new(p).map_err(|e| anyhow!("success regex error: {e}")))
43+
.collect::<Result<Vec<_>, _>>()?;
44+
45+
let fail_regex = fail_patterns
46+
.iter()
47+
.map(|p| Regex::new(p).map_err(|e| anyhow!("fail regex error: {e}")))
48+
.collect::<Result<Vec<_>, _>>()?;
49+
50+
Ok((success_regex, fail_regex))
51+
}
52+
53+
pub(crate) fn print_match_event(matched: &StreamMatch) {
54+
match matched.kind {
55+
StreamMatchKind::Success => println!(
56+
"{}",
57+
format!(
58+
"\n=== SUCCESS PATTERN MATCHED: {} ===",
59+
matched.matched_regex
60+
)
61+
.green()
62+
),
63+
StreamMatchKind::Fail => println!(
64+
"{}",
65+
format!("\n=== FAIL PATTERN MATCHED: {}", matched.matched_regex).red()
66+
),
67+
}
68+
}
69+
2270
#[derive(Debug, Clone)]
2371
enum StreamMatchState {
2472
Pending,

ostool/src/run/qemu.rs

Lines changed: 35 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use tokio::fs;
4343
use crate::{
4444
Tool,
4545
run::{
46-
output_matcher::{ByteStreamMatcher, StreamMatch, StreamMatchKind},
46+
output_matcher::{ByteStreamMatcher, StreamMatch, StreamMatchKind, compile_regexes, print_match_event},
4747
ovmf_prebuilt::{Arch, FileType, Prebuilt, Source},
4848
shell_init::{ShellAutoInitMatcher, normalize_shell_init_config, spawn_delayed_send},
4949
},
@@ -106,6 +106,7 @@ pub struct RunQemuArgs {
106106

107107
#[derive(Debug, Clone, Default)]
108108
struct QemuDefaultOverrides {
109+
to_bin: Option<bool>,
109110
args: Vec<String>,
110111
success_regex: Vec<String>,
111112
fail_regex: Vec<String>,
@@ -126,13 +127,14 @@ struct QemuDefaultOverrides {
126127
/// Returns an error if QEMU fails to start or exits with an error.
127128
impl Tool {
128129
pub async fn run_qemu(&mut self, args: RunQemuArgs) -> anyhow::Result<()> {
129-
self.run_qemu_with_more_default_args(args, vec![], vec![], vec![])
130+
self.run_qemu_with_more_default_args(args, None, vec![], vec![], vec![])
130131
.await
131132
}
132133

133134
pub async fn run_qemu_with_more_default_args(
134135
&mut self,
135136
run_args: RunQemuArgs,
137+
to_bin: Option<bool>,
136138
args: Vec<String>,
137139
success_regex: Vec<String>,
138140
fail_regex: Vec<String>,
@@ -141,6 +143,7 @@ impl Tool {
141143
self,
142144
run_args,
143145
QemuDefaultOverrides {
146+
to_bin,
144147
args,
145148
success_regex,
146149
fail_regex,
@@ -168,30 +171,32 @@ async fn load_or_create_qemu_config(
168171

169172
info!("Using QEMU config file: {}", config_path.display());
170173

171-
if config_path.exists() {
172-
let config_content = fs::read_to_string(&config_path)
173-
.await
174-
.with_path("failed to read file", &config_path)?;
175-
let mut config: QemuConfig = toml::from_str(&config_content)
176-
.with_context(|| format!("failed to parse QEMU config: {}", config_path.display()))?;
177-
config.normalize(&format!("QEMU config {}", config_path.display()))?;
178-
return Ok(config);
179-
}
180-
181-
let mut config = build_default_qemu_config(tool.ctx.arch, overrides);
182-
config.normalize(&format!("QEMU config {}", config_path.display()))?;
183-
fs::write(&config_path, toml::to_string_pretty(&config)?)
184-
.await
185-
.with_path("failed to write file", &config_path)?;
186-
Ok(config)
174+
let config_content = match fs::read_to_string(&config_path).await {
175+
Ok(content) => {
176+
let mut config: QemuConfig = toml::from_str(&content)
177+
.with_context(|| format!("failed to parse QEMU config: {}", config_path.display()))?;
178+
config.normalize(&format!("QEMU config {}", config_path.display()))?;
179+
return Ok(config);
180+
}
181+
Err(e) if e.kind() == io::ErrorKind::NotFound => {
182+
let mut config = build_default_qemu_config(tool.ctx.arch, overrides);
183+
config.normalize(&format!("QEMU config {}", config_path.display()))?;
184+
fs::write(&config_path, toml::to_string_pretty(&config)?)
185+
.await
186+
.with_path("failed to write file", &config_path)?;
187+
config
188+
}
189+
Err(e) => return Err(e.into()),
190+
};
191+
Ok(config_content)
187192
}
188193

189194
fn build_default_qemu_config(
190195
arch: Option<Architecture>,
191196
overrides: QemuDefaultOverrides,
192197
) -> QemuConfig {
193198
let mut config = QemuConfig {
194-
to_bin: true,
199+
to_bin: overrides.to_bin.unwrap_or(true),
195200
success_regex: overrides.success_regex,
196201
fail_regex: overrides.fail_regex,
197202
..Default::default()
@@ -222,7 +227,6 @@ async fn run_qemu_with_config(
222227
let mut runner = QemuRunner {
223228
tool,
224229
config,
225-
args: vec![],
226230
dtbdump: run_args.dtb_dump,
227231
success_regex: vec![],
228232
fail_regex: vec![],
@@ -233,7 +237,6 @@ async fn run_qemu_with_config(
233237
struct QemuRunner<'a> {
234238
tool: &'a mut Tool,
235239
config: QemuConfig,
236-
args: Vec<String>,
237240
dtbdump: bool,
238241
success_regex: Vec<regex::Regex>,
239242
fail_regex: Vec<regex::Regex>,
@@ -262,7 +265,7 @@ impl Drop for RawModeGuard {
262265

263266
impl QemuRunner<'_> {
264267
async fn run(&mut self) -> anyhow::Result<()> {
265-
self.preper_regex()?;
268+
self.prepare_regex()?;
266269

267270
if self.config.to_bin {
268271
self.tool.objcopy_output_bin()?;
@@ -281,14 +284,6 @@ impl QemuRunner<'_> {
281284

282285
let mut need_machine = true;
283286

284-
for arg in &self.config.args {
285-
if arg == "-machine" || arg == "-M" {
286-
need_machine = false;
287-
}
288-
289-
self.args.push(arg.clone());
290-
}
291-
292287
#[allow(unused_mut)]
293288
let mut qemu_executable = format!("qemu-system-{}", arch);
294289

@@ -308,6 +303,9 @@ impl QemuRunner<'_> {
308303
let mut cmd = self.tool.command(&qemu_executable);
309304

310305
for arg in &self.config.args {
306+
if arg == "-machine" || arg == "-M" {
307+
need_machine = false;
308+
}
311309
cmd.arg(arg);
312310
}
313311

@@ -549,7 +547,7 @@ impl QemuRunner<'_> {
549547
let _ = std::io::stdout().flush();
550548

551549
if let Some(matched) = matcher.observe_byte(byte) {
552-
Self::print_match_event(&matched);
550+
print_match_event(&matched);
553551
}
554552

555553
if let Some(shell_auto_init) = shell_auto_init.as_mut()
@@ -606,23 +604,6 @@ impl QemuRunner<'_> {
606604
});
607605
}
608606

609-
fn print_match_event(matched: &StreamMatch) {
610-
match matched.kind {
611-
StreamMatchKind::Success => println!(
612-
"{}",
613-
format!(
614-
"\n=== SUCCESS PATTERN MATCHED: {} ===",
615-
matched.matched_regex
616-
)
617-
.green()
618-
),
619-
StreamMatchKind::Fail => println!(
620-
"{}",
621-
format!("\n=== FAIL PATTERN MATCHED: {} ===", matched.matched_regex).red()
622-
),
623-
}
624-
}
625-
626607
fn kill_qemu(child: &mut Child) -> anyhow::Result<()> {
627608
if let Err(err) = child.kill()
628609
&& err.kind() != ErrorKind::InvalidInput
@@ -646,23 +627,10 @@ impl QemuRunner<'_> {
646627
Ok(())
647628
}
648629

649-
fn preper_regex(&mut self) -> anyhow::Result<()> {
650-
// Prepare regex patterns if needed
651-
// Compile success regex patterns
652-
for pattern in self.config.success_regex.iter() {
653-
// Compile and store the regex
654-
let regex =
655-
regex::Regex::new(pattern).map_err(|e| anyhow!("success regex error: {e}"))?;
656-
self.success_regex.push(regex);
657-
}
658-
659-
// Compile fail regex patterns
660-
for pattern in self.config.fail_regex.iter() {
661-
// Compile and store the regex
662-
let regex = regex::Regex::new(pattern).map_err(|e| anyhow!("fail regex error: {e}"))?;
663-
self.fail_regex.push(regex);
664-
}
665-
630+
fn prepare_regex(&mut self) -> anyhow::Result<()> {
631+
let (success, fail) = compile_regexes(&self.config.success_regex, &self.config.fail_regex)?;
632+
self.success_regex = success;
633+
self.fail_regex = fail;
666634
Ok(())
667635
}
668636
}
@@ -790,11 +758,13 @@ mod tests {
790758
let config = build_default_qemu_config(
791759
Some(Architecture::X86_64),
792760
QemuDefaultOverrides {
761+
to_bin: Some(false),
793762
args: vec!["-smp".into(), "2".into()],
794763
..Default::default()
795764
},
796765
);
797766

767+
assert!(!config.to_bin);
798768
assert_eq!(config.args, vec!["-nographic", "-smp", "2"]);
799769
}
800770

0 commit comments

Comments
 (0)