use crate::driver::base::uevent::kobject_uevent::kobject_uevent_env; use core::fmt::Write; /* Struct kset_uevent_ops Function get_ktype kobject_name kset_get kset_put to_kset */ use crate::driver::base::kobject::KObject; use crate::driver::net::Iface; use crate::filesystem::sysfs::{Attribute, SysFSOpsSupport, SYSFS_ATTR_MODE_RW}; use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; use intertrait::cast::CastArc; use log::warn; use system_error::SystemError; use super::block::block_device::{BlockDevice, BlockDeviceOps}; use super::char::CharDevice; use super::device::{Device, DeviceType}; pub mod kobject_uevent; // https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c?fi=kobject_uevent#457 #[derive(Debug)] pub enum KobjectAction { KOBJADD, KOBJREMOVE, // Kobject(或上层数据结构)的添加/移除事件 KOBJCHANGE, // Kobject(或上层数据结构)的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内,或者是自定义的事件,可以使用该event,并携带相应的参数。 KOBJMOVE, // Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构) KOBJONLINE, KOBJOFFLINE, // Kobject(或上层数据结构)的上线/下线事件,其实是是否使能 KOBJBIND, KOBJUNBIND, } /// 解析一个字符串,以确定它代表的是哪个 kobject_action,并提取出随后的参数(如果有的话) fn kobject_action_type(buf: &[u8]) -> Result<(KobjectAction, Vec), SystemError> { let mut action = KobjectAction::KOBJCHANGE; let mut action_args: Vec = Vec::new(); let mut count = buf.len(); if count != 0 && (buf[count - 1] == b'\n' || buf[count - 1] == b'\0') { count -= 1; } if count == 0 { return Err(SystemError::EINVAL); } let arg_start = buf.iter().position(|&c| c == b' ').unwrap_or(count); let count_first = arg_start; let args_start = arg_start + 1; // 匹配KobjectAction match &buf[..count_first] { b"add" => action = KobjectAction::KOBJADD, b"remove" => action = KobjectAction::KOBJREMOVE, b"change" => action = KobjectAction::KOBJCHANGE, b"move" => action = KobjectAction::KOBJMOVE, b"online" => action = KobjectAction::KOBJONLINE, b"offline" => action = KobjectAction::KOBJOFFLINE, b"bind" => action = KobjectAction::KOBJBIND, b"unbind" => action = KobjectAction::KOBJUNBIND, _ => return Err(SystemError::EINVAL), } // 如果有参数,提取参数 if count - args_start > 0 { action_args = buf[args_start..] .split(|&c| c == b' ') .map(|s| String::from_utf8_lossy(s).to_string()) .collect::>(); } Ok((action, action_args)) } pub const UEVENT_NUM_ENVP: usize = 64; pub const UEVENT_BUFFER_SIZE: usize = 2048; pub const UEVENT_HELPER_PATH_LEN: usize = 256; /// 表示处理内核对象 uevents 的环境 /// - envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。 /// - envp_idx,用于访问环境变量指针数组的index。 /// - buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。 /// - buflen,访问buf的变量。 // https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31 #[derive(Debug)] pub struct KobjUeventEnv { argv: Vec, envp: Vec, envp_idx: usize, buf: Vec, buflen: usize, } // kset_uevent_ops是为kset量身订做的一个数据结构,里面包含filter和uevent两个回调函数,用处如下: /* filter,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口过滤,阻止不希望上报的event,从而达到从整体上管理的目的。 name,该接口可以返回kset的名称。如果一个kset没有合法的名称,则其下的所有Kobject将不允许上报uvent uevent,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的,因此可以由kset统一处理,就不需要让每个Kobject独自添加了。 */ /// 设备文件夹下的`uevent`文件的属性 #[derive(Debug, Clone, Copy)] pub struct UeventAttr; impl Attribute for UeventAttr { fn name(&self) -> &str { "uevent" } fn mode(&self) -> crate::filesystem::vfs::syscall::ModeType { SYSFS_ATTR_MODE_RW } fn support(&self) -> crate::filesystem::sysfs::SysFSOpsSupport { SysFSOpsSupport::ATTR_SHOW | SysFSOpsSupport::ATTR_STORE } /// 用户空间读取 uevent 文件,返回 uevent 信息 fn show(&self, _kobj: Arc, _buf: &mut [u8]) -> Result { let device = _kobj.cast::().map_err(|e: Arc| { warn!("device:{:?} is not a device!", e); SystemError::EINVAL })?; log::info!("show uevent"); let device_type = device.dev_type(); let mut uevent_content = String::new(); log::info!("device_type: {:?}", device_type); match device_type { DeviceType::Block => { let major = device.id_table().device_number().major().data(); let minor = device.id_table().device_number().minor(); let device_name = device.id_table().name(); writeln!(&mut uevent_content, "MAJOR={:?}", major).unwrap(); writeln!(&mut uevent_content, "MINOR={:?}", minor).unwrap(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE=disk").unwrap(); } DeviceType::Char => { let major = device.id_table().device_number().major().data(); let minor = device.id_table().device_number().minor(); let device_name = device.id_table().name(); writeln!(&mut uevent_content, "MAJOR={}", major).unwrap(); writeln!(&mut uevent_content, "MINOR={}", minor).unwrap(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE=char").unwrap(); } DeviceType::Net => { let net_device = device .clone() .cast::() .map_err(|e: Arc| { warn!("device:{:?} is not a net device!", e); SystemError::EINVAL })?; let iface_id = net_device.nic_id(); let device_name = device.name(); writeln!(&mut uevent_content, "INTERFACE={}", device_name).unwrap(); writeln!(&mut uevent_content, "IFINDEX={}", iface_id).unwrap(); } DeviceType::Bus => { // 处理总线设备类型 let device_name = device.name(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE=bus").unwrap(); } DeviceType::Rtc => { // 处理RTC设备类型 let device_name = device.name(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE=rtc").unwrap(); } DeviceType::Pci => { // 处理PCI设备类型 let device_name = device.name(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE=pci").unwrap(); } _ => { // 处理其他设备类型 let device_name = device.name(); writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap(); writeln!(&mut uevent_content, "DEVTYPE={:?}", device_type).unwrap(); } } sysfs_emit_str(_buf, &uevent_content) } /// 捕获来自用户空间对 uevent 文件的写操作,触发uevent事件 fn store(&self, _kobj: Arc, _buf: &[u8]) -> Result { log::info!("store uevent"); return kobject_synth_uevent(_buf, _kobj); } } /// 将设备的基本信息写入 uevent 文件 fn sysfs_emit_str(buf: &mut [u8], content: &str) -> Result { log::info!("sysfs_emit_str"); let bytes = content.as_bytes(); if buf.len() < bytes.len() { return Err(SystemError::ENOMEM); } buf[..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) } /// 解析用户空间写入的 uevent 信息,触发 uevent 事件 fn kobject_synth_uevent(buf: &[u8], kobj: Arc) -> Result { let no_uuid_envp = vec!["SYNTH_UUID=0".to_string()]; let (action, action_args) = kobject_action_type(buf)?; let result = if action_args.is_empty() { kobject_uevent_env(kobj.clone(), action, no_uuid_envp) } else { kobject_uevent_env(kobj.clone(), action, action_args) }; if let Err(e) = result { let device = kobj.cast::().map_err(|e: Arc| { warn!("device:{:?} is not a device!", e); SystemError::EINVAL })?; let devname = device.name(); log::error!("synth uevent: {}: {:?}", devname, e); return Err(SystemError::EINVAL); } Ok(buf.len()) }