mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
Add support for reading hypervisor console (#344)
* feature(xencall): add hypervisor SYSCTL_readconsole definitions * feature(hypervisor-dmesg): xencall: add read_console_ring_raw hypercall wrapper * feature(hypervisor-dmesg): protobuf: add ReadHypervisorConsoleRing RPC * feature(hypervisor-dmesg): runtime: add read_hypervisor_console wrapper * feature(hypervisor-dmesg): daemon: add ReadHypervisorConsoleRing rpc implementation * feature(hypervisor-dmesg): ctl: add host hypervisor-messages command to get hypervisor messages * feature(hypervisor-dmesg): cli: rename hypervisor-messages command to hv-console * feature(hypervisor-dmesg): proto: change ReadHypervisorConsoleRing to ReadHypervisorConsole * feature(hypervisor-dmesg): fix up kratactl protobuf calls
This commit is contained in:
parent
2519d76479
commit
2ab2cda937
24
crates/ctl/src/cli/host/hv_console.rs
Normal file
24
crates/ctl/src/cli/host/hv_console.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use clap::Parser;
|
||||||
|
use krata::v1::control::{
|
||||||
|
control_service_client::ControlServiceClient, ReadHypervisorConsoleRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tonic::{transport::Channel, Request};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about = "Display hypervisor diagnostic messages")]
|
||||||
|
pub struct HostHvConsoleCommand {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostHvConsoleCommand {
|
||||||
|
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
|
||||||
|
let response = client
|
||||||
|
.read_hypervisor_console(Request::new(ReadHypervisorConsoleRequest {}))
|
||||||
|
.await?
|
||||||
|
.into_inner();
|
||||||
|
|
||||||
|
print!("{}", response.data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,12 @@ use krata::v1::control::control_service_client::ControlServiceClient;
|
|||||||
use crate::cli::host::cpu_topology::HostCpuTopologyCommand;
|
use crate::cli::host::cpu_topology::HostCpuTopologyCommand;
|
||||||
use crate::cli::host::identify::HostStatusCommand;
|
use crate::cli::host::identify::HostStatusCommand;
|
||||||
use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
|
use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
|
||||||
|
use crate::cli::host::hv_console::HostHvConsoleCommand;
|
||||||
|
|
||||||
pub mod cpu_topology;
|
pub mod cpu_topology;
|
||||||
pub mod identify;
|
pub mod identify;
|
||||||
pub mod idm_snoop;
|
pub mod idm_snoop;
|
||||||
|
pub mod hv_console;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(about = "Manage the host of the isolation engine")]
|
#[command(about = "Manage the host of the isolation engine")]
|
||||||
@ -35,6 +37,7 @@ pub enum HostCommands {
|
|||||||
CpuTopology(HostCpuTopologyCommand),
|
CpuTopology(HostCpuTopologyCommand),
|
||||||
Status(HostStatusCommand),
|
Status(HostStatusCommand),
|
||||||
IdmSnoop(HostIdmSnoopCommand),
|
IdmSnoop(HostIdmSnoopCommand),
|
||||||
|
HvConsole(HostHvConsoleCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HostCommands {
|
impl HostCommands {
|
||||||
@ -49,6 +52,8 @@ impl HostCommands {
|
|||||||
HostCommands::Status(status) => status.run(client).await,
|
HostCommands::Status(status) => status.run(client).await,
|
||||||
|
|
||||||
HostCommands::IdmSnoop(snoop) => snoop.run(client, events).await,
|
HostCommands::IdmSnoop(snoop) => snoop.run(client, events).await,
|
||||||
|
|
||||||
|
HostCommands::HvConsole(hvconsole) => hvconsole.run(client).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ use krata::{
|
|||||||
ReadZoneMetricsReply, ReadZoneMetricsRequest, ResolveZoneIdReply, ResolveZoneIdRequest,
|
ReadZoneMetricsReply, ReadZoneMetricsRequest, ResolveZoneIdReply, ResolveZoneIdRequest,
|
||||||
SnoopIdmReply, SnoopIdmRequest, UpdateZoneResourcesReply, UpdateZoneResourcesRequest,
|
SnoopIdmReply, SnoopIdmRequest, UpdateZoneResourcesReply, UpdateZoneResourcesRequest,
|
||||||
WatchEventsReply, WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest,
|
WatchEventsReply, WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest,
|
||||||
|
ReadHypervisorConsoleRequest, ReadHypervisorConsoleReply,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -710,4 +711,14 @@ impl ControlService for DaemonControlService {
|
|||||||
.map_err(ApiError::from)?;
|
.map_err(ApiError::from)?;
|
||||||
Ok(Response::new(UpdateZoneResourcesReply {}))
|
Ok(Response::new(UpdateZoneResourcesReply {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn read_hypervisor_console(
|
||||||
|
&self,
|
||||||
|
_request: Request<ReadHypervisorConsoleRequest>,
|
||||||
|
) -> Result<Response<ReadHypervisorConsoleReply>, Status> {
|
||||||
|
let data = self.runtime.read_hypervisor_console(false).await.map_err(|error| ApiError {
|
||||||
|
message: error.to_string(),
|
||||||
|
})?;
|
||||||
|
Ok(Response::new(ReadHypervisorConsoleReply { data: data.to_string() }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ service ControlService {
|
|||||||
rpc ReadZoneMetrics(ReadZoneMetricsRequest) returns (ReadZoneMetricsReply);
|
rpc ReadZoneMetrics(ReadZoneMetricsRequest) returns (ReadZoneMetricsReply);
|
||||||
|
|
||||||
rpc WatchEvents(WatchEventsRequest) returns (stream WatchEventsReply);
|
rpc WatchEvents(WatchEventsRequest) returns (stream WatchEventsReply);
|
||||||
|
|
||||||
|
rpc ReadHypervisorConsole(ReadHypervisorConsoleRequest) returns (ReadHypervisorConsoleReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
message HostStatusRequest {}
|
message HostStatusRequest {}
|
||||||
@ -252,3 +254,9 @@ message UpdateZoneResourcesRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message UpdateZoneResourcesReply {}
|
message UpdateZoneResourcesReply {}
|
||||||
|
|
||||||
|
message ReadHypervisorConsoleRequest {}
|
||||||
|
|
||||||
|
message ReadHypervisorConsoleReply {
|
||||||
|
string data = 1;
|
||||||
|
}
|
||||||
|
@ -297,4 +297,14 @@ impl Runtime {
|
|||||||
let context = RuntimeContext::new().await?;
|
let context = RuntimeContext::new().await?;
|
||||||
Ok(PowerManagementContext { context })
|
Ok(PowerManagementContext { context })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_hypervisor_console(&self, clear: bool) -> Result<Arc<str>> {
|
||||||
|
let index = 0 as u32;
|
||||||
|
let (rawbuf, newindex) = self.context
|
||||||
|
.xen
|
||||||
|
.call
|
||||||
|
.read_console_ring_raw(clear, index).await?;
|
||||||
|
let buf = std::str::from_utf8(&rawbuf[..newindex as usize])?;
|
||||||
|
Ok(Arc::from(buf))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
18
crates/xen/xencall/examples/console_read.rs
Normal file
18
crates/xen/xencall/examples/console_read.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use xencall::error::Result;
|
||||||
|
use xencall::XenCall;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let call = XenCall::open(0)?;
|
||||||
|
let index = 0 as u32;
|
||||||
|
let (buf, newindex) = call.read_console_ring_raw(false, index).await?;
|
||||||
|
|
||||||
|
match std::str::from_utf8(&buf[..newindex as usize]) {
|
||||||
|
Ok(v) => print!("{}", v),
|
||||||
|
_ => panic!("unable to decode Xen console messages"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -26,12 +26,12 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use sys::{
|
use sys::{
|
||||||
CpuId, E820Entry, ForeignMemoryMap, PhysdevMapPirq, Sysctl, SysctlCputopo, SysctlCputopoinfo,
|
CpuId, E820Entry, ForeignMemoryMap, PhysdevMapPirq, Sysctl, SysctlCputopo, SysctlCputopoinfo,
|
||||||
SysctlPhysinfo, SysctlPmOp, SysctlPmOpValue, SysctlSetCpuFreqGov, SysctlValue,
|
SysctlPhysinfo, SysctlPmOp, SysctlPmOpValue, SysctlSetCpuFreqGov, SysctlValue, SysctlReadconsole,
|
||||||
VcpuGuestContextAny, HYPERVISOR_PHYSDEV_OP, HYPERVISOR_SYSCTL, PHYSDEVOP_MAP_PIRQ,
|
VcpuGuestContextAny, HYPERVISOR_PHYSDEV_OP, HYPERVISOR_SYSCTL, PHYSDEVOP_MAP_PIRQ,
|
||||||
XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION, XEN_MEM_SET_MEMORY_MAP,
|
XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION, XEN_MEM_SET_MEMORY_MAP,
|
||||||
XEN_SYSCTL_CPUTOPOINFO, XEN_SYSCTL_MAX_INTERFACE_VERSION, XEN_SYSCTL_MIN_INTERFACE_VERSION,
|
XEN_SYSCTL_CPUTOPOINFO, XEN_SYSCTL_MAX_INTERFACE_VERSION, XEN_SYSCTL_MIN_INTERFACE_VERSION,
|
||||||
XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO,
|
XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO,
|
||||||
XEN_SYSCTL_PM_OP_ENABLE_TURBO, XEN_SYSCTL_PM_OP_SET_CPUFREQ_GOV,
|
XEN_SYSCTL_PM_OP_ENABLE_TURBO, XEN_SYSCTL_PM_OP_SET_CPUFREQ_GOV, XEN_SYSCTL_READCONSOLE,
|
||||||
};
|
};
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
@ -1087,4 +1087,31 @@ impl XenCall {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_console_ring_raw(&self, clear: bool, index: u32) -> Result<([u8; 16384], u32)> {
|
||||||
|
let mut u8buf = [0u8; 16384];
|
||||||
|
let mut sysctl = Sysctl {
|
||||||
|
cmd: XEN_SYSCTL_READCONSOLE,
|
||||||
|
interface_version: self.sysctl_interface_version,
|
||||||
|
value: SysctlValue {
|
||||||
|
console: SysctlReadconsole {
|
||||||
|
clear: clear as u8,
|
||||||
|
incremental: 1,
|
||||||
|
pad: 0,
|
||||||
|
index: index,
|
||||||
|
buffer: addr_of_mut!(u8buf) as u64,
|
||||||
|
count: 16384,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
||||||
|
.await?;
|
||||||
|
// Safety: We are passing a SysctlReadconsole struct as part of the hypercall, and
|
||||||
|
// calling the hypercall is known to not change the underlying value outside changing
|
||||||
|
// the values on some SysctlReadconsole fields.
|
||||||
|
let newindex = unsafe {
|
||||||
|
sysctl.value.console.index
|
||||||
|
};
|
||||||
|
Ok((u8buf, newindex))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,6 +752,7 @@ pub struct SysctlCputopoinfo {
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub union SysctlValue {
|
pub union SysctlValue {
|
||||||
|
pub console: SysctlReadconsole,
|
||||||
pub cputopoinfo: SysctlCputopoinfo,
|
pub cputopoinfo: SysctlCputopoinfo,
|
||||||
pub pm_op: SysctlPmOp,
|
pub pm_op: SysctlPmOp,
|
||||||
pub phys_info: SysctlPhysinfo,
|
pub phys_info: SysctlPhysinfo,
|
||||||
@ -765,6 +766,7 @@ pub struct Sysctl {
|
|||||||
pub value: SysctlValue,
|
pub value: SysctlValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const XEN_SYSCTL_READCONSOLE: u32 = 1;
|
||||||
pub const XEN_SYSCTL_PHYSINFO: u32 = 3;
|
pub const XEN_SYSCTL_PHYSINFO: u32 = 3;
|
||||||
pub const XEN_SYSCTL_PM_OP: u32 = 12;
|
pub const XEN_SYSCTL_PM_OP: u32 = 12;
|
||||||
pub const XEN_SYSCTL_CPUTOPOINFO: u32 = 16;
|
pub const XEN_SYSCTL_CPUTOPOINFO: u32 = 16;
|
||||||
@ -802,3 +804,14 @@ pub struct SysctlPhysinfo {
|
|||||||
pub max_mfn: u64,
|
pub max_mfn: u64,
|
||||||
pub hw_cap: [u32; 8],
|
pub hw_cap: [u32; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct SysctlReadconsole {
|
||||||
|
pub clear: u8,
|
||||||
|
pub incremental: u8,
|
||||||
|
pub pad: u16,
|
||||||
|
pub index: u32,
|
||||||
|
pub buffer: u64,
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user