From b7d101b98c52c73a83a6266c2fc3d7c48921915a Mon Sep 17 00:00:00 2001 From: Hsy-Intel Date: Wed, 16 Oct 2024 15:01:22 +0000 Subject: [PATCH] Fix MMIO read issue --- .../comps/virtio/src/device/input/device.rs | 60 ++++++++++++------- kernel/comps/virtio/src/device/input/mod.rs | 16 ++--- .../comps/virtio/src/device/network/config.rs | 17 ++++-- 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/kernel/comps/virtio/src/device/input/device.rs b/kernel/comps/virtio/src/device/input/device.rs index a91cab04c..2378603f3 100644 --- a/kernel/comps/virtio/src/device/input/device.rs +++ b/kernel/comps/virtio/src/device/input/device.rs @@ -32,7 +32,7 @@ bitflags! { /// The properties of input device. /// /// Ref: Linux input-event-codes.h - pub struct InputProp : u8{ + pub struct InputProp : u8 { /// Needs a pointer const POINTER = 1 << 0; /// Direct input devices @@ -112,15 +112,15 @@ impl InputDevice { callbacks: RwLock::new(Vec::new()), }); - let mut raw_name: [u8; 128] = [0; 128]; - device.query_config_select(InputConfigSelect::IdName, 0, &mut raw_name); - let name = String::from_utf8(raw_name.to_vec()).unwrap(); + let name = device.query_config_id_name(); info!("Virtio input device name:{}", name); - let mut prop: [u8; 128] = [0; 128]; - device.query_config_select(InputConfigSelect::PropBits, 0, &mut prop); - let input_prop = InputProp::from_bits(prop[0]).unwrap(); - debug!("input device prop:{:?}", input_prop); + let input_prop = device.query_config_prop_bits(); + if let Some(prop) = input_prop { + debug!("input device prop: {:?}", prop); + } else { + debug!("input device has no properties or the properties is not defined"); + } let mut transport = device.transport.disable_irq().lock(); fn config_space_change(_: &TrapFrame) { @@ -167,25 +167,45 @@ impl InputDevice { } } - /// Query a specific piece of information by `select` and `subsel`, and write - /// result to `out`, return the result size. - pub fn query_config_select(&self, select: InputConfigSelect, subsel: u8, out: &mut [u8]) -> u8 { + pub fn query_config_id_name(&self) -> String { + let size = self.select_config(InputConfigSelect::IdName, 0); + + let out = { + // TODO: Add a general API to read this byte-by-byte. + let mut out = Vec::with_capacity(size); + let mut data_ptr = field_ptr!(&self.config, VirtioInputConfig, data).cast::(); + for _ in 0..size { + out.push(data_ptr.read_once().unwrap()); + data_ptr.byte_add(1); + } + out + }; + + String::from_utf8(out).unwrap() + } + + pub fn query_config_prop_bits(&self) -> Option { + let size = self.select_config(InputConfigSelect::PropBits, 0); + if size == 0 { + return None; + } + assert!(size == 1); + + let data_ptr = field_ptr!(&self.config, VirtioInputConfig, data); + InputProp::from_bits(data_ptr.cast::().read_once().unwrap()) + } + + /// Query a specific piece of information by `select` and `subsel`, return the result size. + fn select_config(&self, select: InputConfigSelect, subsel: u8) -> usize { field_ptr!(&self.config, VirtioInputConfig, select) .write_once(&(select as u8)) .unwrap(); field_ptr!(&self.config, VirtioInputConfig, subsel) .write_once(&subsel) .unwrap(); - let size = field_ptr!(&self.config, VirtioInputConfig, size) + field_ptr!(&self.config, VirtioInputConfig, size) .read_once() - .unwrap(); - let data: [u8; 128] = field_ptr!(&self.config, VirtioInputConfig, data) - // FIXME: It is impossible to call `read_once` on `[u8; 128]`. What's the proper way to - // read this field out? - .read() - .unwrap(); - out[..size as usize].copy_from_slice(&data[..size as usize]); - size + .unwrap() as usize } fn handle_irq(&self) { diff --git a/kernel/comps/virtio/src/device/input/mod.rs b/kernel/comps/virtio/src/device/input/mod.rs index 2823eaee1..c3d005d50 100644 --- a/kernel/comps/virtio/src/device/input/mod.rs +++ b/kernel/comps/virtio/src/device/input/mod.rs @@ -38,24 +38,26 @@ pub static DEVICE_NAME: &str = "Virtio-Input"; #[repr(u8)] #[derive(Debug, Clone, Copy)] pub enum InputConfigSelect { - /// Returns the name of the device, in u.string. subsel is zero. + /// Invalid configuration selection. + Unset = 0x00, + /// Returns the name of the device, subsel is zero. IdName = 0x01, - /// Returns the serial number of the device, in u.string. subsel is zero. + /// Returns the serial number of the device, subsel is zero. IdSerial = 0x02, - /// Returns ID information of the device, in u.ids. subsel is zero. + /// Returns ID information of the device, subsel is zero. IdDevids = 0x03, - /// Returns input properties of the device, in u.bitmap. subsel is zero. + /// Returns input properties of the device, subsel is zero. /// Individual bits in the bitmap correspond to INPUT_PROP_* constants used /// by the underlying evdev implementation. PropBits = 0x10, /// subsel specifies the event type using EV_* constants in the underlying /// evdev implementation. If size is non-zero the event type is supported - /// and a bitmap of supported event codes is returned in u.bitmap. Individual + /// and a bitmap of supported event codes is returned. Individual /// bits in the bitmap correspond to implementation-defined input event codes, /// for example keys or pointing device axes. EvBits = 0x11, /// subsel specifies the absolute axis using ABS_* constants in the underlying - /// evdev implementation. Information about the axis will be returned in u.abs. + /// evdev implementation. Information about the axis will be returned. AbsInfo = 0x12, } @@ -92,7 +94,7 @@ struct AbsInfo { #[repr(C)] #[derive(Debug, Copy, Clone, Pod)] -struct DevIDs { +struct DevIds { bustype: u16, vendor: u16, product: u16, diff --git a/kernel/comps/virtio/src/device/network/config.rs b/kernel/comps/virtio/src/device/network/config.rs index d09d49847..2026361d5 100644 --- a/kernel/comps/virtio/src/device/network/config.rs +++ b/kernel/comps/virtio/src/device/network/config.rs @@ -3,7 +3,7 @@ use aster_network::EthernetAddr; use aster_util::{field_ptr, safe_ptr::SafePtr}; use bitflags::bitflags; -use ostd::{io_mem::IoMem, Pod}; +use ostd::{io_mem::IoMem, offset_of, Pod}; use crate::transport::VirtioTransport; @@ -78,10 +78,19 @@ impl VirtioNetConfig { } pub(super) fn read(this: &SafePtr) -> ostd::prelude::Result { + // TODO: Add a general API to read this byte-by-byte. + let mac_data = { + let mut mac_data: [u8; 6] = [0; 6]; + let mut mac_ptr = field_ptr!(this, Self, mac).cast::(); + for byte in &mut mac_data { + *byte = mac_ptr.read_once().unwrap(); + mac_ptr.byte_add(1); + } + mac_data + }; + Ok(Self { - // FIXME: It is impossible to call `read_once` on `EthernetAddr`. What's the proper way - // to read this field out? - mac: field_ptr!(this, Self, mac).read()?, + mac: aster_network::EthernetAddr(mac_data), status: field_ptr!(this, Self, status).read_once()?, max_virtqueue_pairs: field_ptr!(this, Self, max_virtqueue_pairs).read_once()?, mtu: field_ptr!(this, Self, mtu).read_once()?,