arguments: document and add pnam tag

The `PNam` tag stores information in the kernel about process names.
This can be used at runtime to discover what process maps to what
program name.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2021-05-10 14:12:19 +08:00
parent 4bb355aec6
commit 2e4fb672ab
4 changed files with 93 additions and 0 deletions

View file

@ -125,3 +125,15 @@ offsets must be in the range `0xffc0_0000` - `0xfff0_0000`.
* ENTRYPOINT -- Virtual address of the `_start()` function
The kernel will run in Supervisor mode, and have its own private stack.
### PNam
`PNam` maps process IDs to process names. If multiple `PNam` tags exist
within a block, the first one that is encountered should take precedence.
This tag is a series of entries that take the following format:
| Size (bytes) | Name | Description
| --------- | ---- | -----
| 4 | PID | ID of the process that this name describes
| 4 | Length | The length of the data that follows
| varies | Data | The UTF-8 name string

View file

@ -10,6 +10,7 @@ use tools::elf::{read_minielf, read_program};
use tools::tags::bflg::Bflg;
use tools::tags::inie::IniE;
use tools::tags::memory::{MemoryRegion, MemoryRegions};
use tools::tags::pnam::ProcessNames;
use tools::tags::xkrn::XousKernel;
use tools::utils::{parse_csr_csv, parse_u32};
use tools::xous_arguments::XousArguments;
@ -138,6 +139,8 @@ fn main() {
memory_required: 0,
};
let mut process_names = ProcessNames::new();
if let Some(val) = matches.value_of("ram") {
let ram_parts: Vec<&str> = val.split(':').collect();
if ram_parts.len() != 2 {
@ -224,8 +227,20 @@ fn main() {
)
.expect("unable to read kernel");
process_names.set(1, "kernel");
if let Some(init_paths) = matches.values_of("init") {
let mut pid = 2;
for init_path in init_paths {
let program_name = std::path::Path::new(init_path);
process_names.set(
pid,
program_name
.file_stem()
.expect("program had no name")
.to_str()
.expect("program name is not valid utf-8"),
);
pid += 1;
let init = read_minielf(init_path).expect("couldn't parse init file");
args.add(IniE::new(init.entry_point, init.sections, init.program));
}
@ -242,6 +257,8 @@ fn main() {
);
args.add(xkrn);
args.add(process_names);
// Add tags for init and kernel. These point to the actual data, which should
// immediately follow the tags. Therefore, we must know the length of the tags
// before we create them.

View file

@ -1,4 +1,5 @@
pub mod bflg;
pub mod inie;
pub mod memory;
pub mod pnam;
pub mod xkrn;

63
tools/src/tags/pnam.rs Normal file
View file

@ -0,0 +1,63 @@
use crate::xous_arguments::{XousArgument, XousArgumentCode, XousSize};
use std::fmt;
use std::io;
use std::collections::BTreeMap;
#[derive(Debug)]
pub struct ProcessNames {
/// A vec of all known process names
names: BTreeMap<u32, String>,
}
impl fmt::Display for ProcessNames {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, " process names:")?;
for (pid, name) in self.names.iter() {
writeln!(f, " PID {}: {}", pid, name)?;
}
Ok(())
}
}
impl ProcessNames {
pub fn new() -> ProcessNames {
ProcessNames { names: BTreeMap::new() }
}
pub fn set(&mut self, pid: u32, name: &str) {
self.names.insert(pid, name.to_owned());
}
}
impl XousArgument for ProcessNames {
fn code(&self) -> XousArgumentCode {
u32::from_le_bytes(*b"PNam")
}
fn length(&self) -> XousSize {
let mut size = 0;
for val in self.names.values() {
size += 4;
size += 4;
size += val.len();
// Pad it to 4-bytes
size += (4-(val.len() & 3))&3;
}
size as XousSize
}
fn serialize(&self, output: &mut dyn io::Write) -> io::Result<usize> {
let mut written = 0;
for (pid, name) in self.names.iter() {
written += output.write(&(*pid as u32).to_le_bytes())?;
written += output.write(&(name.len() as u32).to_le_bytes())?;
written += output.write(name.as_bytes())?;
// Pad it to 4-bytes
for _ in 0..(4-(name.len() & 3))&3 {
written += output.write(&[0])?;
}
}
Ok(written)
}
}