Calling mmap on dumbbuffer with Linux’ Direct Rendering Manager in Rust fails while working in C
一段时间以来,我一直在使用Linux的Direct Rendering Manager,它可以执行非常低级的图形管理。这通常是在C中借助libdrm或直接使用DRM标头完成的。
我正在尝试在Rust中创建一个与libdrm等效的文件,这不仅是对C库的绑定,而是直接使用syscalls。鉴于目前几乎没有有关DRM的文档,这并不是一件容易的事,但是我正在C中跟踪此示例以获取有关从何处开始的提示。
我现在已经到达创建一个哑缓冲并将其映射到内存中的位置,这样我就可以修改每个像素在屏幕上显示的像素了。为此,我必须使用
这是C语言中最少的工作代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include <errno.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <drm/drm.h> #include <drm/drm_mode.h> #include <sys/ioctl.h> #include <sys/mman.h> int main() { // STEP 1: GET ACCESS TODRM int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); if (fd < 0) { printf("Error in function open(): %s\ ", strerror(errno)); return 1; } // STEP 2: CREATE DUMBBUFFER struct drm_mode_create_dumb dreq; dreq.height = 1080, dreq.width = 1920, dreq.bpp = 32, dreq.flags = 0, dreq.handle = 0, dreq.pitch = 0, dreq.size = 0; int ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dreq); if (ret == -1) { printf("Call to DRM_IOCTL_MODE_CREATE_DUMB failed: %s\ ", strerror(errno)); return 1; } // STEP 3: ADD FRAMEBUFFER struct drm_mode_fb_cmd creq; creq.fb_id = 0; creq.width = dreq.width; creq.height = dreq.height; creq.pitch = dreq.pitch; creq.bpp = dreq.bpp; creq.depth = 24; creq.handle = dreq.handle; ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &creq); if (ret == -1) { printf("Call to DRM_IOCTL_MODE_ADDFB failed: %s\ ", strerror(errno)); return 1; } // STEP 4: PREPARE FORMAPPING struct drm_mode_map_dumb mreq; mreq.handle = dreq.handle; mreq.pad = 0; mreq.offset = 0; ret = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); if (ret == -1) { printf("Call to DRM_IOCTL_MODE_MAP_DUMB failed: %s\ ", strerror(errno)); return 1; } // STEP 5: MAPPINGPROPER void *map = mmap(0, dreq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); if (map == MAP_FAILED) { printf("Error in function mmap(): %s\ ", strerror(errno)); return 1; } else { printf("Address of mapped data: 0x%x\ ", map); } return 0; } |
这与Rust中的代码完全相同。当然,我的实际代码中包含很多东西,但是这一最小的代码足以得到错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #![feature(libc)] extern crate libc; use self::libc::{c_char, c_int, c_ulong, c_void, off_t, size_t}; extern { pub fn ioctl(fd : c_int, request : c_ulong, arg : *mut c_void) -> c_int; } fn errno() -> c_int { unsafe { *libc::__errno_location() } } fn get_c_error() -> String { unsafe { let strerr = libc::strerror(errno()) as *mut u8; let length = libc::strlen(strerr as *const c_char) as usize; let mut string = String::with_capacity(length); for i in 0..length { let car = *strerr.offset(i as isize) as char; if car == (0 as char) { break; } string.push(car); } string } } #[repr(C)] struct CCreateDumb { height : u32, width : u32, bpp : u32, _flags : u32, handle : u32, pitch : u32, size : u64, } #[repr(C)] struct CFrameBuffer { _fb_id : u32, _width : u32, _height : u32, _pitch : u32, _bpp : u32, _depth : u32, _handle : u32, } #[repr(C)] struct CMapDumb { _handle : u32, _pad : u32, offset : u32, } fn main() { // STEP 1: GET ACCESS TODRM let pathname ="/dev/dri/card0".to_string(); let fd : c_int = unsafe { libc::open(pathname.as_ptr() as *const c_char, libc::O_RDWR | libc::O_CLOEXEC) }; if fd < 0 { panic!("Error in call of C function open(): {}", get_c_error()); } // STEP 2: CREATE DUMBBUFFER let mut dreq = CCreateDumb { height : 1080, width : 1920, bpp : 32, _flags : 0, handle : 0, pitch : 0, size : 0, }; // NB?: 0xc02064b2 = DRM_IOCTL_MODE_CREATE_DUMB let mut ret = unsafe { ioctl(fd, 0xc02064b2 as c_ulong, &mut dreq as *mut _ as *mut c_void) }; if ret == -1 { panic!("Call to DRM_IOCTL_MODE_CREATE_DUMB failed: {}", get_c_error()); } // STEP 3: ADD FRAMEBUFFER let mut creq = CFrameBuffer { _fb_id : 0, _width : dreq.width, _height : dreq.height, _pitch : dreq.pitch, _bpp : dreq.bpp, _depth : 24, _handle : dreq.handle, }; // NB?: 0xc01c64ae = DRM_IOCTL_MODE_ADDFB ret = unsafe { ioctl(fd, 0xc01c64ae as c_ulong, &mut creq as *mut _ as *mut c_void) }; if ret == -1 { panic!("Call to DRM_IOCTL_MODE_ADDFB failed: {}", get_c_error()); } // STEP 4: PREPARE FORMAPPING let mut mreq = CMapDumb { _handle : dreq.handle, _pad : 0, offset : 0, }; // NB?: 0xc01064b3 = DRM_IOCTL_MODE_MAP_DUMB ret = unsafe { ioctl(fd, 0xc01064b3 as c_ulong, &mut mreq as *mut _ as *mut c_void) }; if ret == -1 { panic!("Call to DRM_IOCTL_MODE_MAP_DUMB failed: {}", get_c_error()); } // STEP 5: MAPPINGPROPER let map = unsafe { libc::mmap( 0 as *mut c_void, dreq.size as size_t, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED, fd, mreq.offset as off_t ) }; if map == libc::MAP_FAILED { panic!("Error in call of C function mmap(): {}", get_c_error()); } else { println!("Address of mapped data: 0x{:p}", map); } } |
它可以正常编译,但是当我执行它时,会出现此错误。
thread '' panicked at 'Error in call of C function mmap(): Invalid argument', memmapping.rs:139
note: Run withRUST_BACKTRACE=1 for a backtrace.
使用
我看了看这个项目如何命名为
这个SO问题使用名为
因此,我按照Shepmaster的建议使用了