741f144c79
- Add full VirtIO GPU driver with command submission, resource management, VirtQueue implementation, and transport layer; includes diagnostic probes for resource_create_2d ERR_INVALID_RESOURCE_ID investigation - Expand libdrm Redox support with DRM ioctl wrappers (ADDFB, RMFB, CREATE_DUMB, MAP_DUMB, DESTROY_DUMB, GET_RESOURCES, GET_CONNECTOR, GET_CRTC, SET_CRTC, MODE_OBJ_GET_PROPERTIES, etc.) and xf86drm_redox.h - Add redox-drm scheme handlers for VirtIO GPU-specific DRM ioctls (VIRTGPU_RESOURCE_CREATE, VIRTGPU_MAP, VIRTGPU_WAIT, VIRTGPU_INFO, etc.) - Add display stack recipes: freetype2, lcms2, libdisplay-info, libepoxy, libxcvt - Fix KWin build (recipe.toml expanded, kf6-ksvg added) - Fix KF6 CMakeLists for cross-compilation (attica, kcmutils, kcolorscheme, kcompletion, kconfigwidgets, kdeclarative, kiconthemes, kitemmodels, kitemviews, kjobwidgets, ktextwidgets, kwayland, kxmlgui, kpty, solid) - Add Qt6 futex support patch - Add relibc patches: P3 strtold, P3 ld-so search path, P5 DRM ioctl removal - Add base P4 pcid config scheme patch - Update driver-manager hotplug/config, PCI config in redox-driver-sys - Update greeter compositor and KDE session scripts - Update AGENTS.md with zero-tolerance stubs policy and project knowledge
201 lines
6.9 KiB
Diff
201 lines
6.9 KiB
Diff
diff --git a/drivers/pcid/src/cfg_access/fallback.rs b/drivers/pcid/src/cfg_access/fallback.rs
|
|
--- a/drivers/pcid/src/cfg_access/fallback.rs
|
|
+++ b/drivers/pcid/src/cfg_access/fallback.rs
|
|
@@ -61,8 +61,11 @@
|
|
|
|
Self::set_iopl();
|
|
|
|
- let offset =
|
|
- u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
|
+ let Ok(offset) = u8::try_from(offset) else {
|
|
+ // Offset exceeds 256-byte PCI 3.0 config space — return all-ones
|
|
+ // (standard response for non-existent config space, matching Linux behavior).
|
|
+ return 0xFFFF_FFFF;
|
|
+ };
|
|
let address = Self::address(address, offset);
|
|
|
|
Pio::<u32>::new(0xCF8).write(address);
|
|
@@ -74,8 +77,9 @@
|
|
|
|
Self::set_iopl();
|
|
|
|
- let offset =
|
|
- u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
|
+ let Ok(offset) = u8::try_from(offset) else {
|
|
+ return;
|
|
+ };
|
|
let address = Self::address(address, offset);
|
|
|
|
Pio::<u32>::new(0xCF8).write(address);
|
|
diff --git a/drivers/pcid/src/scheme.rs b/drivers/pcid/src/scheme.rs
|
|
--- a/drivers/pcid/src/scheme.rs
|
|
+++ b/drivers/pcid/src/scheme.rs
|
|
@@ -22,6 +22,7 @@
|
|
Access,
|
|
Device,
|
|
Channel { addr: PciAddress, st: ChannelState },
|
|
+ Config { addr: PciAddress },
|
|
SchemeRoot,
|
|
}
|
|
struct HandleWrapper {
|
|
@@ -30,14 +31,20 @@
|
|
}
|
|
impl Handle {
|
|
fn is_file(&self) -> bool {
|
|
- matches!(self, Self::Access | Self::Channel { .. })
|
|
+ matches!(
|
|
+ self,
|
|
+ Self::Access | Self::Channel { .. } | Self::Config { .. }
|
|
+ )
|
|
}
|
|
fn is_dir(&self) -> bool {
|
|
!self.is_file()
|
|
}
|
|
// TODO: capability rather than root
|
|
fn requires_root(&self) -> bool {
|
|
- matches!(self, Self::Access | Self::Channel { .. })
|
|
+ matches!(
|
|
+ self,
|
|
+ Self::Access | Self::Channel { .. } | Self::Config { .. }
|
|
+ )
|
|
}
|
|
fn is_scheme_root(&self) -> bool {
|
|
matches!(self, Self::SchemeRoot)
|
|
@@ -49,7 +56,8 @@
|
|
AwaitingResponseRead(VecDeque<u8>),
|
|
}
|
|
|
|
-const DEVICE_CONTENTS: &[&str] = &["channel"];
|
|
+const DEVICE_CONTENTS: &[&str] = &["channel", "config"];
|
|
+const STANDARD_CONFIG_SPACE_SIZE: usize = 256;
|
|
|
|
impl PciScheme {
|
|
pub fn access(&mut self) -> usize {
|
|
@@ -133,6 +141,7 @@
|
|
Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755),
|
|
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
|
|
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
|
|
+ Handle::Config { .. } => (STANDARD_CONFIG_SPACE_SIZE, MODE_CHR | 0o600),
|
|
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
|
};
|
|
stat.st_size = len as u64;
|
|
@@ -143,7 +152,7 @@
|
|
&mut self,
|
|
id: usize,
|
|
buf: &mut [u8],
|
|
- _offset: u64,
|
|
+ offset: u64,
|
|
_fcntl_flags: u32,
|
|
_ctx: &CallerCtx,
|
|
) -> Result<usize> {
|
|
@@ -160,6 +169,7 @@
|
|
addr: _,
|
|
ref mut st,
|
|
} => Self::read_channel(st, buf),
|
|
+ Handle::Config { addr } => Self::read_config(&self.pcie, addr, buf, offset),
|
|
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
|
_ => Err(Error::new(EBADF)),
|
|
}
|
|
@@ -193,7 +203,9 @@
|
|
return Ok(buf);
|
|
}
|
|
Handle::Device => DEVICE_CONTENTS,
|
|
- Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)),
|
|
+ Handle::Access | Handle::Channel { .. } | Handle::Config { .. } => {
|
|
+ return Err(Error::new(ENOTDIR));
|
|
+ }
|
|
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
|
};
|
|
|
|
@@ -212,7 +224,7 @@
|
|
&mut self,
|
|
id: usize,
|
|
buf: &[u8],
|
|
- _offset: u64,
|
|
+ offset: u64,
|
|
_fcntl_flags: u32,
|
|
_ctx: &CallerCtx,
|
|
) -> Result<usize> {
|
|
@@ -226,6 +238,7 @@
|
|
Handle::Channel { addr, ref mut st } => {
|
|
Self::write_channel(&self.pcie, &mut self.tree, addr, st, buf)
|
|
}
|
|
+ Handle::Config { addr } => Self::write_config(&self.pcie, addr, buf, offset),
|
|
|
|
_ => Err(Error::new(EBADF)),
|
|
}
|
|
@@ -356,11 +369,73 @@
|
|
st: ChannelState::AwaitingData,
|
|
}
|
|
}
|
|
+ "config" => Handle::Config { addr },
|
|
_ => return Err(Error::new(ENOENT)),
|
|
}
|
|
})
|
|
}
|
|
|
|
+ fn read_config(pcie: &Pcie, addr: PciAddress, buf: &mut [u8], offset: u64) -> Result<usize> {
|
|
+ let start = usize::try_from(offset).map_err(|_| Error::new(EINVAL))?;
|
|
+ let end = start.saturating_add(buf.len()).min(STANDARD_CONFIG_SPACE_SIZE);
|
|
+ if start >= end {
|
|
+ return Ok(0);
|
|
+ }
|
|
+
|
|
+ let aligned_start = start & !0x3;
|
|
+ let aligned_end = (end + 3) & !0x3;
|
|
+
|
|
+ let mut bytes_read = 0;
|
|
+ for dword_offset in (aligned_start..aligned_end).step_by(4) {
|
|
+ let bytes = unsafe { pcie.read(addr, dword_offset as u16) }.to_le_bytes();
|
|
+
|
|
+ let chunk_start = start.max(dword_offset);
|
|
+ let chunk_end = end.min(dword_offset + bytes.len());
|
|
+ let src_start = chunk_start - dword_offset;
|
|
+ let dst_start = chunk_start - start;
|
|
+ let len = chunk_end - chunk_start;
|
|
+
|
|
+ buf[dst_start..dst_start + len].copy_from_slice(&bytes[src_start..src_start + len]);
|
|
+ bytes_read += len;
|
|
+ }
|
|
+
|
|
+ Ok(bytes_read)
|
|
+ }
|
|
+
|
|
+ fn write_config(pcie: &Pcie, addr: PciAddress, buf: &[u8], offset: u64) -> Result<usize> {
|
|
+ let start = usize::try_from(offset).map_err(|_| Error::new(EINVAL))?;
|
|
+ let end = start.saturating_add(buf.len()).min(STANDARD_CONFIG_SPACE_SIZE);
|
|
+ if start >= end {
|
|
+ return Ok(0);
|
|
+ }
|
|
+
|
|
+ let aligned_start = start & !0x3;
|
|
+ let aligned_end = (end + 3) & !0x3;
|
|
+
|
|
+ let mut bytes_written = 0;
|
|
+ for dword_offset in (aligned_start..aligned_end).step_by(4) {
|
|
+ let chunk_start = start.max(dword_offset);
|
|
+ let chunk_end = end.min(dword_offset + 4);
|
|
+ let dst_start = chunk_start - dword_offset;
|
|
+ let src_start = chunk_start - start;
|
|
+ let len = chunk_end - chunk_start;
|
|
+
|
|
+ let mut bytes = if dst_start == 0 && len == 4 {
|
|
+ [0; 4]
|
|
+ } else {
|
|
+ unsafe { pcie.read(addr, dword_offset as u16) }.to_le_bytes()
|
|
+ };
|
|
+ bytes[dst_start..dst_start + len].copy_from_slice(&buf[src_start..src_start + len]);
|
|
+
|
|
+ unsafe {
|
|
+ pcie.write(addr, dword_offset as u16, u32::from_le_bytes(bytes));
|
|
+ }
|
|
+ bytes_written += len;
|
|
+ }
|
|
+
|
|
+ Ok(bytes_written)
|
|
+ }
|
|
+
|
|
fn read_channel(state: &mut ChannelState, buf: &mut [u8]) -> Result<usize> {
|
|
match *state {
|
|
ChannelState::AwaitingResponseRead(ref mut queue) => {
|