gpu.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. //! Driver for VirtIO GPU devices.
  2. use crate::hal::{BufferDirection, Dma, Hal};
  3. use crate::queue::VirtQueue;
  4. use crate::transport::Transport;
  5. use crate::volatile::{volread, ReadOnly, Volatile, WriteOnly};
  6. use crate::{pages, Error, Result};
  7. use bitflags::bitflags;
  8. use log::info;
  9. /// A virtio based graphics adapter.
  10. ///
  11. /// It can operate in 2D mode and in 3D (virgl) mode.
  12. /// 3D mode will offload rendering ops to the host gpu and therefore requires
  13. /// a gpu with 3D support on the host machine.
  14. /// In 2D mode the virtio-gpu device provides support for ARGB Hardware cursors
  15. /// and multiple scanouts (aka heads).
  16. pub struct VirtIOGpu<'a, H: Hal, T: Transport> {
  17. transport: T,
  18. rect: Option<Rect>,
  19. /// DMA area of frame buffer.
  20. frame_buffer_dma: Option<Dma<H>>,
  21. /// DMA area of cursor image buffer.
  22. cursor_buffer_dma: Option<Dma<H>>,
  23. /// Queue for sending control commands.
  24. control_queue: VirtQueue<H>,
  25. /// Queue for sending cursor commands.
  26. cursor_queue: VirtQueue<H>,
  27. /// DMA region for sending data to the device.
  28. dma_send: Dma<H>,
  29. /// DMA region for receiving data from the device.
  30. dma_recv: Dma<H>,
  31. /// Send buffer for queue.
  32. queue_buf_send: &'a mut [u8],
  33. /// Recv buffer for queue.
  34. queue_buf_recv: &'a mut [u8],
  35. }
  36. impl<H: Hal, T: Transport> VirtIOGpu<'_, H, T> {
  37. /// Create a new VirtIO-Gpu driver.
  38. pub fn new(mut transport: T) -> Result<Self> {
  39. transport.begin_init(|features| {
  40. let features = Features::from_bits_truncate(features);
  41. info!("Device features {:?}", features);
  42. let supported_features = Features::empty();
  43. (features & supported_features).bits()
  44. });
  45. // read configuration space
  46. let config_space = transport.config_space::<Config>()?;
  47. unsafe {
  48. let events_read = volread!(config_space, events_read);
  49. let num_scanouts = volread!(config_space, num_scanouts);
  50. info!(
  51. "events_read: {:#x}, num_scanouts: {:#x}",
  52. events_read, num_scanouts
  53. );
  54. }
  55. let control_queue = VirtQueue::new(&mut transport, QUEUE_TRANSMIT, 2)?;
  56. let cursor_queue = VirtQueue::new(&mut transport, QUEUE_CURSOR, 2)?;
  57. let dma_send = Dma::new(1, BufferDirection::DriverToDevice)?;
  58. let dma_recv = Dma::new(1, BufferDirection::DeviceToDriver)?;
  59. let queue_buf_send = unsafe { dma_send.raw_slice().as_mut() };
  60. let queue_buf_recv = unsafe { dma_recv.raw_slice().as_mut() };
  61. transport.finish_init();
  62. Ok(VirtIOGpu {
  63. transport,
  64. frame_buffer_dma: None,
  65. cursor_buffer_dma: None,
  66. rect: None,
  67. control_queue,
  68. cursor_queue,
  69. dma_send,
  70. dma_recv,
  71. queue_buf_send,
  72. queue_buf_recv,
  73. })
  74. }
  75. /// Acknowledge interrupt.
  76. pub fn ack_interrupt(&mut self) -> bool {
  77. self.transport.ack_interrupt()
  78. }
  79. /// Get the resolution (width, height).
  80. pub fn resolution(&mut self) -> Result<(u32, u32)> {
  81. let display_info = self.get_display_info()?;
  82. Ok((display_info.rect.width, display_info.rect.height))
  83. }
  84. /// Setup framebuffer
  85. pub fn setup_framebuffer(&mut self) -> Result<&mut [u8]> {
  86. // get display info
  87. let display_info = self.get_display_info()?;
  88. info!("=> {:?}", display_info);
  89. self.rect = Some(display_info.rect);
  90. // create resource 2d
  91. self.resource_create_2d(
  92. RESOURCE_ID_FB,
  93. display_info.rect.width,
  94. display_info.rect.height,
  95. )?;
  96. // alloc continuous pages for the frame buffer
  97. let size = display_info.rect.width * display_info.rect.height * 4;
  98. let frame_buffer_dma = Dma::new(pages(size as usize), BufferDirection::DriverToDevice)?;
  99. // resource_attach_backing
  100. self.resource_attach_backing(RESOURCE_ID_FB, frame_buffer_dma.paddr() as u64, size)?;
  101. // map frame buffer to screen
  102. self.set_scanout(display_info.rect, SCANOUT_ID, RESOURCE_ID_FB)?;
  103. let buf = unsafe { frame_buffer_dma.raw_slice().as_mut() };
  104. self.frame_buffer_dma = Some(frame_buffer_dma);
  105. Ok(buf)
  106. }
  107. /// Flush framebuffer to screen.
  108. pub fn flush(&mut self) -> Result {
  109. let rect = self.rect.ok_or(Error::NotReady)?;
  110. // copy data from guest to host
  111. self.transfer_to_host_2d(rect, 0, RESOURCE_ID_FB)?;
  112. // flush data to screen
  113. self.resource_flush(rect, RESOURCE_ID_FB)?;
  114. Ok(())
  115. }
  116. /// Set the pointer shape and position.
  117. pub fn setup_cursor(
  118. &mut self,
  119. cursor_image: &[u8],
  120. pos_x: u32,
  121. pos_y: u32,
  122. hot_x: u32,
  123. hot_y: u32,
  124. ) -> Result {
  125. let size = CURSOR_RECT.width * CURSOR_RECT.height * 4;
  126. if cursor_image.len() != size as usize {
  127. return Err(Error::InvalidParam);
  128. }
  129. let cursor_buffer_dma = Dma::new(pages(size as usize), BufferDirection::DriverToDevice)?;
  130. let buf = unsafe { cursor_buffer_dma.raw_slice().as_mut() };
  131. buf.copy_from_slice(cursor_image);
  132. self.resource_create_2d(RESOURCE_ID_CURSOR, CURSOR_RECT.width, CURSOR_RECT.height)?;
  133. self.resource_attach_backing(RESOURCE_ID_CURSOR, cursor_buffer_dma.paddr() as u64, size)?;
  134. self.transfer_to_host_2d(CURSOR_RECT, 0, RESOURCE_ID_CURSOR)?;
  135. self.update_cursor(
  136. RESOURCE_ID_CURSOR,
  137. SCANOUT_ID,
  138. pos_x,
  139. pos_y,
  140. hot_x,
  141. hot_y,
  142. false,
  143. )?;
  144. self.cursor_buffer_dma = Some(cursor_buffer_dma);
  145. Ok(())
  146. }
  147. /// Move the pointer without updating the shape.
  148. pub fn move_cursor(&mut self, pos_x: u32, pos_y: u32) -> Result {
  149. self.update_cursor(RESOURCE_ID_CURSOR, SCANOUT_ID, pos_x, pos_y, 0, 0, true)?;
  150. Ok(())
  151. }
  152. /// Send a request to the device and block for a response.
  153. fn request<Req, Rsp>(&mut self, req: Req) -> Result<Rsp> {
  154. unsafe {
  155. (self.queue_buf_send.as_mut_ptr() as *mut Req).write(req);
  156. }
  157. self.control_queue.add_notify_wait_pop(
  158. &[self.queue_buf_send],
  159. &[self.queue_buf_recv],
  160. &mut self.transport,
  161. )?;
  162. Ok(unsafe { (self.queue_buf_recv.as_ptr() as *const Rsp).read() })
  163. }
  164. /// Send a mouse cursor operation request to the device and block for a response.
  165. fn cursor_request<Req>(&mut self, req: Req) -> Result {
  166. unsafe {
  167. (self.queue_buf_send.as_mut_ptr() as *mut Req).write(req);
  168. }
  169. self.cursor_queue
  170. .add_notify_wait_pop(&[self.queue_buf_send], &[], &mut self.transport)?;
  171. Ok(())
  172. }
  173. fn get_display_info(&mut self) -> Result<RespDisplayInfo> {
  174. let info: RespDisplayInfo = self.request(CtrlHeader::with_type(Command::GetDisplayInfo))?;
  175. info.header.check_type(Command::OkDisplayInfo)?;
  176. Ok(info)
  177. }
  178. fn resource_create_2d(&mut self, resource_id: u32, width: u32, height: u32) -> Result {
  179. let rsp: CtrlHeader = self.request(ResourceCreate2D {
  180. header: CtrlHeader::with_type(Command::ResourceCreate2d),
  181. resource_id,
  182. format: Format::B8G8R8A8UNORM,
  183. width,
  184. height,
  185. })?;
  186. rsp.check_type(Command::OkNodata)
  187. }
  188. fn set_scanout(&mut self, rect: Rect, scanout_id: u32, resource_id: u32) -> Result {
  189. let rsp: CtrlHeader = self.request(SetScanout {
  190. header: CtrlHeader::with_type(Command::SetScanout),
  191. rect,
  192. scanout_id,
  193. resource_id,
  194. })?;
  195. rsp.check_type(Command::OkNodata)
  196. }
  197. fn resource_flush(&mut self, rect: Rect, resource_id: u32) -> Result {
  198. let rsp: CtrlHeader = self.request(ResourceFlush {
  199. header: CtrlHeader::with_type(Command::ResourceFlush),
  200. rect,
  201. resource_id,
  202. _padding: 0,
  203. })?;
  204. rsp.check_type(Command::OkNodata)
  205. }
  206. fn transfer_to_host_2d(&mut self, rect: Rect, offset: u64, resource_id: u32) -> Result {
  207. let rsp: CtrlHeader = self.request(TransferToHost2D {
  208. header: CtrlHeader::with_type(Command::TransferToHost2d),
  209. rect,
  210. offset,
  211. resource_id,
  212. _padding: 0,
  213. })?;
  214. rsp.check_type(Command::OkNodata)
  215. }
  216. fn resource_attach_backing(&mut self, resource_id: u32, paddr: u64, length: u32) -> Result {
  217. let rsp: CtrlHeader = self.request(ResourceAttachBacking {
  218. header: CtrlHeader::with_type(Command::ResourceAttachBacking),
  219. resource_id,
  220. nr_entries: 1,
  221. addr: paddr,
  222. length,
  223. _padding: 0,
  224. })?;
  225. rsp.check_type(Command::OkNodata)
  226. }
  227. fn update_cursor(
  228. &mut self,
  229. resource_id: u32,
  230. scanout_id: u32,
  231. pos_x: u32,
  232. pos_y: u32,
  233. hot_x: u32,
  234. hot_y: u32,
  235. is_move: bool,
  236. ) -> Result {
  237. self.cursor_request(UpdateCursor {
  238. header: if is_move {
  239. CtrlHeader::with_type(Command::MoveCursor)
  240. } else {
  241. CtrlHeader::with_type(Command::UpdateCursor)
  242. },
  243. pos: CursorPos {
  244. scanout_id,
  245. x: pos_x,
  246. y: pos_y,
  247. _padding: 0,
  248. },
  249. resource_id,
  250. hot_x,
  251. hot_y,
  252. _padding: 0,
  253. })
  254. }
  255. }
  256. impl<H: Hal, T: Transport> Drop for VirtIOGpu<'_, H, T> {
  257. fn drop(&mut self) {
  258. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  259. // after they have been freed.
  260. self.transport.queue_unset(QUEUE_TRANSMIT);
  261. self.transport.queue_unset(QUEUE_CURSOR);
  262. }
  263. }
  264. #[repr(C)]
  265. struct Config {
  266. /// Signals pending events to the driver。
  267. events_read: ReadOnly<u32>,
  268. /// Clears pending events in the device.
  269. events_clear: WriteOnly<u32>,
  270. /// Specifies the maximum number of scanouts supported by the device.
  271. ///
  272. /// Minimum value is 1, maximum value is 16.
  273. num_scanouts: Volatile<u32>,
  274. }
  275. /// Display configuration has changed.
  276. const EVENT_DISPLAY: u32 = 1 << 0;
  277. bitflags! {
  278. struct Features: u64 {
  279. /// virgl 3D mode is supported.
  280. const VIRGL = 1 << 0;
  281. /// EDID is supported.
  282. const EDID = 1 << 1;
  283. // device independent
  284. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  285. const ANY_LAYOUT = 1 << 27; // legacy
  286. const RING_INDIRECT_DESC = 1 << 28;
  287. const RING_EVENT_IDX = 1 << 29;
  288. const UNUSED = 1 << 30; // legacy
  289. const VERSION_1 = 1 << 32; // detect legacy
  290. // since virtio v1.1
  291. const ACCESS_PLATFORM = 1 << 33;
  292. const RING_PACKED = 1 << 34;
  293. const IN_ORDER = 1 << 35;
  294. const ORDER_PLATFORM = 1 << 36;
  295. const SR_IOV = 1 << 37;
  296. const NOTIFICATION_DATA = 1 << 38;
  297. }
  298. }
  299. #[repr(u32)]
  300. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  301. enum Command {
  302. GetDisplayInfo = 0x100,
  303. ResourceCreate2d = 0x101,
  304. ResourceUnref = 0x102,
  305. SetScanout = 0x103,
  306. ResourceFlush = 0x104,
  307. TransferToHost2d = 0x105,
  308. ResourceAttachBacking = 0x106,
  309. ResourceDetachBacking = 0x107,
  310. GetCapsetInfo = 0x108,
  311. GetCapset = 0x109,
  312. GetEdid = 0x10a,
  313. UpdateCursor = 0x300,
  314. MoveCursor = 0x301,
  315. OkNodata = 0x1100,
  316. OkDisplayInfo = 0x1101,
  317. OkCapsetInfo = 0x1102,
  318. OkCapset = 0x1103,
  319. OkEdid = 0x1104,
  320. ErrUnspec = 0x1200,
  321. ErrOutOfMemory = 0x1201,
  322. ErrInvalidScanoutId = 0x1202,
  323. }
  324. const GPU_FLAG_FENCE: u32 = 1 << 0;
  325. #[repr(C)]
  326. #[derive(Debug, Clone, Copy)]
  327. struct CtrlHeader {
  328. hdr_type: Command,
  329. flags: u32,
  330. fence_id: u64,
  331. ctx_id: u32,
  332. _padding: u32,
  333. }
  334. impl CtrlHeader {
  335. fn with_type(hdr_type: Command) -> CtrlHeader {
  336. CtrlHeader {
  337. hdr_type,
  338. flags: 0,
  339. fence_id: 0,
  340. ctx_id: 0,
  341. _padding: 0,
  342. }
  343. }
  344. /// Return error if the type is not same as expected.
  345. fn check_type(&self, expected: Command) -> Result {
  346. if self.hdr_type == expected {
  347. Ok(())
  348. } else {
  349. Err(Error::IoError)
  350. }
  351. }
  352. }
  353. #[repr(C)]
  354. #[derive(Debug, Copy, Clone, Default)]
  355. struct Rect {
  356. x: u32,
  357. y: u32,
  358. width: u32,
  359. height: u32,
  360. }
  361. #[repr(C)]
  362. #[derive(Debug)]
  363. struct RespDisplayInfo {
  364. header: CtrlHeader,
  365. rect: Rect,
  366. enabled: u32,
  367. flags: u32,
  368. }
  369. #[repr(C)]
  370. #[derive(Debug)]
  371. struct ResourceCreate2D {
  372. header: CtrlHeader,
  373. resource_id: u32,
  374. format: Format,
  375. width: u32,
  376. height: u32,
  377. }
  378. #[repr(u32)]
  379. #[derive(Debug)]
  380. enum Format {
  381. B8G8R8A8UNORM = 1,
  382. }
  383. #[repr(C)]
  384. #[derive(Debug)]
  385. struct ResourceAttachBacking {
  386. header: CtrlHeader,
  387. resource_id: u32,
  388. nr_entries: u32, // always 1
  389. addr: u64,
  390. length: u32,
  391. _padding: u32,
  392. }
  393. #[repr(C)]
  394. #[derive(Debug)]
  395. struct SetScanout {
  396. header: CtrlHeader,
  397. rect: Rect,
  398. scanout_id: u32,
  399. resource_id: u32,
  400. }
  401. #[repr(C)]
  402. #[derive(Debug)]
  403. struct TransferToHost2D {
  404. header: CtrlHeader,
  405. rect: Rect,
  406. offset: u64,
  407. resource_id: u32,
  408. _padding: u32,
  409. }
  410. #[repr(C)]
  411. #[derive(Debug)]
  412. struct ResourceFlush {
  413. header: CtrlHeader,
  414. rect: Rect,
  415. resource_id: u32,
  416. _padding: u32,
  417. }
  418. #[repr(C)]
  419. #[derive(Debug, Clone, Copy)]
  420. struct CursorPos {
  421. scanout_id: u32,
  422. x: u32,
  423. y: u32,
  424. _padding: u32,
  425. }
  426. #[repr(C)]
  427. #[derive(Debug, Clone, Copy)]
  428. struct UpdateCursor {
  429. header: CtrlHeader,
  430. pos: CursorPos,
  431. resource_id: u32,
  432. hot_x: u32,
  433. hot_y: u32,
  434. _padding: u32,
  435. }
  436. const QUEUE_TRANSMIT: u16 = 0;
  437. const QUEUE_CURSOR: u16 = 1;
  438. const SCANOUT_ID: u32 = 0;
  439. const RESOURCE_ID_FB: u32 = 0xbabe;
  440. const RESOURCE_ID_CURSOR: u32 = 0xdade;
  441. const CURSOR_RECT: Rect = Rect {
  442. x: 0,
  443. y: 0,
  444. width: 64,
  445. height: 64,
  446. };