mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
+ Sort and group the imports + Normalize and format comments (100 characters width) Command used: $ cargo +nightly fmt -- Acked-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Marc Hartmayer <marc@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
255 lines
8.5 KiB
Rust
255 lines
8.5 KiB
Rust
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright IBM Corp. 2024
|
|
|
|
mod cli;
|
|
mod msa;
|
|
mod query;
|
|
mod stfle;
|
|
|
|
use std::io::ErrorKind;
|
|
use std::result::Result::Ok;
|
|
|
|
use anyhow::{bail, Result as anyhowRes};
|
|
use clap::Parser;
|
|
use utils::print_version;
|
|
|
|
use crate::cli::{Cli, Format};
|
|
use crate::msa::*;
|
|
use crate::query::*;
|
|
use crate::stfle::*;
|
|
|
|
/// producing -m/--msa output
|
|
fn out_msa(args: &Cli, levels: &Vec<MsaLevel>, instructions: &Vec<Instruction>) {
|
|
// produce json output
|
|
if args.format == Format::Json {
|
|
println!("{}", serde_json::to_string(levels).unwrap());
|
|
return;
|
|
}
|
|
|
|
// produce human readable output
|
|
for lvl in levels {
|
|
// print current level
|
|
println!("{lvl}");
|
|
|
|
// if -f/--functions is not specified continue to next level
|
|
if !args.functions {
|
|
continue;
|
|
}
|
|
|
|
// print all functions introduced by the current level sorted by instruction
|
|
for ins in instructions {
|
|
// skip instructions for which the current level introduces no new functions
|
|
if !args.instructions.contains(&ins.kind) && !args.instructions.is_empty()
|
|
|| !ins.info.available
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// filter all functions that do not fit the command line arguments
|
|
let funcs_to_be_printed = ins
|
|
.funcs
|
|
.iter()
|
|
.filter(|func| {
|
|
!(!func.available && !args.not_available
|
|
|| func.available && !args.available && args.not_available)
|
|
})
|
|
.filter(|func| func.msa == lvl.msa_level);
|
|
|
|
// print all functions matching the command line arguments
|
|
let mut ins_printed = false;
|
|
for func in funcs_to_be_printed {
|
|
if !ins_printed {
|
|
println!("\t{ins}");
|
|
ins_printed = true;
|
|
}
|
|
println!("\t\t{func}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// produces output for all cpacfinfo commands that do not contain the -m/--msa flag
|
|
fn out_instructions(args: &Cli, instructions: &Vec<Instruction>) {
|
|
// produce json output
|
|
if args.format == Format::Json {
|
|
println!("{}", serde_json::to_string(instructions).unwrap());
|
|
return;
|
|
}
|
|
|
|
// produce human readable output
|
|
for ins in instructions {
|
|
if !args.instructions.contains(&ins.kind) && !args.instructions.is_empty()
|
|
|| !ins.info.available
|
|
{
|
|
continue;
|
|
}
|
|
println!("{ins}");
|
|
|
|
// --no-auth-info/-n suppresses the Authentication Information output
|
|
if !args.quiet && ins.info.qai_available {
|
|
println!("{}", ins.info.qai);
|
|
} else if !args.quiet {
|
|
println!("Query Authentication Information not available for {ins} instruction! (potentially insufficient machine level)");
|
|
}
|
|
|
|
// --functions/-f lists functions of instructions
|
|
if args.functions {
|
|
ins.funcs
|
|
.iter()
|
|
.filter(|func| {
|
|
!(!func.available && !args.not_available
|
|
|| func.available && !args.available && args.not_available)
|
|
})
|
|
.for_each(|func| println!("\t{func}"));
|
|
println!();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() -> anyhowRes<()> {
|
|
// ---- PARSE COMMAND LINE ARGUMENTS ----
|
|
let args: Cli = Cli::parse();
|
|
|
|
// ---- PRINT VERSION STRING ----
|
|
if args.version {
|
|
print_version!("2024");
|
|
return Ok(());
|
|
}
|
|
|
|
// ---- SET CONSTANTS ----
|
|
let mut instructions = Vec::new();
|
|
init_instructions(&mut instructions);
|
|
|
|
let mut levels = Vec::new();
|
|
for lvl in 0..MSA_LEVEL_COUNT {
|
|
let temp = match num2msa(lvl) {
|
|
Some(l) => l,
|
|
None => panic!("programming error"),
|
|
};
|
|
let stfle_bit = msa2stfle(&temp);
|
|
levels.push(MsaLevel::new(temp, stfle_bit));
|
|
let idx_of_last_element = levels.len() - 1;
|
|
update_msa_function_count(&args, &mut levels[idx_of_last_element], &instructions);
|
|
}
|
|
|
|
// ---- GET INFORMATION ----
|
|
// get stfle bits
|
|
let stfle_bits = Stfle::new()?;
|
|
|
|
// check stfle bits for available MSA levels
|
|
for lvl in &mut levels {
|
|
match lvl.stfle_bit {
|
|
Some(bit) => lvl.enabled = stfle_bits.check_bit_in_stfle(bit),
|
|
None => continue,
|
|
}
|
|
}
|
|
|
|
// check if SYSFS_PATH is available
|
|
match check_sysfs() {
|
|
true => (),
|
|
false => return Ok(()),
|
|
}
|
|
|
|
// run query function (fc 0) for every instruction to check available functions
|
|
for ins in &mut instructions {
|
|
if stfle_bits.check_bit_in_stfle(ins.info.stfle_bit) {
|
|
ins.info.available = true;
|
|
|
|
// run query; save result in param
|
|
let mut param = match query(&ins.kind, QUERY_FUNCTION_CODE) {
|
|
Ok(pb) => match pb {
|
|
Param::QueryParam(_) => pb,
|
|
Param::QaiParam(_) => panic!("programming error"),
|
|
},
|
|
Err(e) => match e.kind() {
|
|
ErrorKind::NotFound => {
|
|
println!("Warning: Not able to retrieve subfunction information from sysfs for {ins} instruction");
|
|
continue;
|
|
}
|
|
_ => return Err(e.into()),
|
|
},
|
|
};
|
|
|
|
// check if bit for functions of current instruction is set in param
|
|
for func in &mut ins.funcs {
|
|
if !param.check_bit_in_param(func.function_code as usize) {
|
|
continue;
|
|
}
|
|
|
|
func.available = true;
|
|
|
|
// unset the bit in param to later see if any unsupported functions may be available
|
|
param.unset_bit_in_param(func.function_code);
|
|
|
|
// check if qai is available
|
|
if func.function_code == QAI_FUNCTION_CODE {
|
|
ins.info.qai_available = true;
|
|
}
|
|
|
|
// sync MsaLevel struct
|
|
for lvl in &mut levels {
|
|
if lvl.msa_level == func.msa {
|
|
lvl.enabled = true;
|
|
lvl.available_functions += 1;
|
|
if args.instructions.is_empty() || args.instructions.contains(&ins.kind) {
|
|
lvl.dynamic_available_functions += 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// look for any unsupported functions that my be available
|
|
for i in 0..NUMBER_FUNC_CODES {
|
|
// every bit in param that is 1 is an unsupported function
|
|
if !param.check_bit_in_param(i) {
|
|
continue;
|
|
}
|
|
|
|
// add function to instruction as UNKNOWN
|
|
Instruction::add(ins, Function::new(i as u8, Msa::UNKNOWN, "UNKNOWN"));
|
|
|
|
// set function as available
|
|
match ins.funcs.last_mut() {
|
|
Some(ret) => ret.available = true,
|
|
None => panic!("programming error"),
|
|
}
|
|
}
|
|
|
|
// if query authentication information (fc 127) available run query authentication
|
|
// information
|
|
if ins.info.qai_available {
|
|
// get qai from sysfs
|
|
let param = match query(&ins.kind, QAI_FUNCTION_CODE) {
|
|
Ok(pb) => match pb {
|
|
Param::QueryParam(_) => panic!("programming error"),
|
|
Param::QaiParam(_) => pb,
|
|
},
|
|
Err(e) => match e.kind() {
|
|
ErrorKind::NotFound => {
|
|
println!("Warning: Not able to retrieve Query Authentication Information from sysfs for {ins} instruction");
|
|
continue;
|
|
}
|
|
_ => return Err(e.into()),
|
|
},
|
|
};
|
|
|
|
// parse qai information into QueryAuthInfo struct
|
|
match param.parse_qai_based_on_format(&mut ins.info.qai) {
|
|
Ok(true) => (),
|
|
Ok(false) => println!("WARNING: format {} in query authentication information of instruction {} is UNKNOWN", ins.info.qai.format, ins.kind),
|
|
Err(e) => bail!(e.to_string()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---- OUTPUT ----
|
|
match args.msa {
|
|
true => out_msa(&args, &levels, &instructions),
|
|
false => out_instructions(&args, &instructions),
|
|
}
|
|
Ok(())
|
|
}
|