feat: add support for dumping VBIOS to a file (#305)

* feat: vbios dump daemon implementation

* feat: vbios dump ui
This commit is contained in:
Ilya Zlobintsev 2024-04-22 20:23:35 +03:00 committed by GitHub
parent 06e061b88e
commit 6dc35200d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 77 additions and 2 deletions

View File

@ -126,6 +126,7 @@ impl DaemonClient {
);
request_with_id!(get_power_states, GetPowerStates, PowerStates);
request_with_id!(reset_pmfw, ResetPmfw, u64);
request_with_id!(dump_vbios, VbiosDump, Vec<u8>);
pub fn set_performance_level(
&self,

View File

@ -28,7 +28,7 @@ use std::{
str::FromStr,
time::Duration,
};
use std::{collections::BTreeMap, time::Instant};
use std::{collections::BTreeMap, fs, time::Instant};
use tokio::{
select,
sync::Notify,
@ -623,6 +623,18 @@ impl GpuController {
}
}
pub fn vbios_dump(&self) -> anyhow::Result<Vec<u8>> {
let debugfs = self.debugfs_path().context("DebugFS not found")?;
fs::read(debugfs.join("amdgpu_vbios")).context("Could not read VBIOS file")
}
fn debugfs_path(&self) -> Option<PathBuf> {
self.handle
.get_pci_slot_name()
.map(|slot_id| Path::new("/sys/kernel/debug/dri").join(slot_id))
.filter(|path| path.exists())
}
#[allow(clippy::too_many_lines)]
pub async fn apply_config(&self, config: &config::Gpu) -> anyhow::Result<()> {
if let Some(cap) = config.power_cap {

View File

@ -463,6 +463,10 @@ impl<'a> Handler {
.context("Failed to edit GPU config and set enabled power states")
}
pub fn vbios_dump(&self, id: &str) -> anyhow::Result<Vec<u8>> {
self.controller_by_id(id)?.vbios_dump()
}
pub async fn generate_snapshot(&self) -> anyhow::Result<String> {
let datetime = chrono::Local::now().format("%Y%m%d-%H%M%S");
let out_path = format!("/tmp/LACT-sysfs-snapshot-{datetime}.tar.gz");

View File

@ -106,6 +106,7 @@ async fn handle_request<'a>(request: Request<'a>, handler: &'a Handler) -> anyho
Request::SetEnabledPowerStates { id, kind, states } => {
ok_response(handler.set_enabled_power_states(id, kind, states).await?)
}
Request::VbiosDump { id } => ok_response(handler.vbios_dump(id)?),
Request::EnableOverdrive => ok_response(system::enable_overdrive().await?),
Request::DisableOverdrive => ok_response(system::disable_overdrive().await?),
Request::GenerateSnapshot => ok_response(handler.generate_snapshot().await?),

View File

@ -26,6 +26,7 @@ impl Header {
Some("Show historical charts"),
Some("app.show-graphs-window"),
);
menu.append(Some("Dump VBIOS"), Some("app.dump-vbios"));
menu.append(
Some("Generate debug snapshot"),
Some("app.generate-debug-snapshot"),

View File

@ -198,7 +198,14 @@ impl App {
}))
.build();
app.application.add_action_entries([snapshot_action, disable_overdive_action, show_graphs_window_action]);
let dump_vbios_action = ActionEntry::builder("dump-vbios")
.activate(clone!(@strong app, @strong current_gpu_id => move |_, _, _| {
let gpu_id = current_gpu_id.borrow();
app.dump_vbios(&gpu_id);
}))
.build();
app.application.add_action_entries([snapshot_action, disable_overdive_action, show_graphs_window_action, dump_vbios_action]);
app.start_stats_update_loop(current_gpu_id);
@ -645,6 +652,52 @@ impl App {
}));
}
fn dump_vbios(&self, gpu_id: &str) {
match self
.daemon_client
.dump_vbios(gpu_id)
.and_then(|response| response.inner())
{
Ok(vbios_data) => {
let file_chooser = FileChooserDialog::new(
Some("Save VBIOS file"),
Some(&self.window),
FileChooserAction::Save,
&[
("Save", ResponseType::Accept),
("Cancel", ResponseType::Cancel),
],
);
let file_name_suffix = gpu_id
.split_once('-')
.map(|(id, _)| id.replace(':', "_"))
.unwrap_or_default();
file_chooser.set_current_name(&format!("{file_name_suffix}_vbios_dump.rom"));
file_chooser.run_async(
clone!(@strong self.window as window => move |diag, _| {
diag.close();
if let Some(file) = diag.file() {
match file.path() {
Some(path) => {
if let Err(err) = std::fs::write(path, vbios_data).context("Could not save vbios file") {
show_error(&window, err);
}
}
None => show_error(
&window,
anyhow!("Selected file has an invalid path"),
),
}
}
}),
);
}
Err(err) => show_error(&self.window, err),
}
}
fn ask_confirmation(&self, gpu_id: String, mut delay: u64) {
let text = confirmation_text(delay);
let dialog = MessageDialog::builder()

View File

@ -52,6 +52,9 @@ pub enum Request<'a> {
kind: PowerLevelKind,
states: Vec<u8>,
},
VbiosDump {
id: &'a str,
},
EnableOverdrive,
DisableOverdrive,
GenerateSnapshot,