Skip to main content

ublk_vram/
lib.rs

1pub mod local;
2pub mod opencl;
3#[path = "ublk/server.rs"]
4mod server;
5
6pub use server::start_ublk_server;
7
8use anyhow::Result;
9pub trait VBuffer: Send + Sync {
10    /// read data from buffer
11    fn read(&self, offset: u64, data: &mut [u8]) -> Result<()>;
12    /// write data to buffer
13    fn write(&self, offset: u64, data: &[u8]) -> Result<()>;
14    /// check remaining parts
15    fn remaining(&self, offset: u64) -> Option<usize>;
16    /// set offset in global area
17    fn offset(&mut self, offset: u64);
18    /// get size of this buffer
19    fn size(&self) -> usize;
20}
21pub struct VMemory<T> {
22    vrams: Vec<T>,
23    size: u64,
24}
25
26unsafe impl<T: VBuffer> Send for VMemory<T> {}
27unsafe impl<T: VBuffer> Sync for VMemory<T> {}
28
29impl<T: VBuffer> VMemory<T> {
30    pub fn new(mut vrams: Vec<T>) -> Self {
31        let mut size: u64 = 0;
32        for i in vrams.iter_mut() {
33            i.offset(size);
34            size += i.size() as u64;
35        }
36        Self { vrams, size }
37    }
38
39    /// # Safety
40    /// data must a validate ptr
41    pub unsafe fn read(&self, offset: u64, length: usize, data: *mut u8) -> i32 {
42        let mut local_offset = 0;
43        let mut global_offset = offset;
44        let mut global_remaining = length;
45        for (i, vram) in self.vrams.iter().enumerate() {
46            let local_remaining = vram.remaining(global_offset);
47            if local_remaining.is_none() {
48                continue;
49            }
50            // compute local length to read/write
51            let local_length = global_remaining.min(local_remaining.unwrap());
52
53            let array = unsafe {
54                std::slice::from_raw_parts_mut(data.add(local_offset), local_length)
55            };
56            if let Err(e) = vram.read(global_offset, array) {
57                log::error!(
58                    "Read error, device vram-{} offset {} size {}, code {}",
59                    i,
60                    global_offset,
61                    local_length,
62                    e
63                );
64                return -libc::EIO;
65            }
66
67            // re-compute rest to read/write
68            global_remaining -= local_length;
69            if global_remaining == 0 {
70                break;
71            }
72            local_offset += local_length;
73            global_offset += local_length as u64;
74        }
75        if global_remaining > 0 {
76            log::error!(
77                "Read error, offset {} size {}",
78                global_offset,
79                global_remaining
80            );
81            return -libc::EIO;
82        }
83        length as i32
84    }
85
86    /// # Safety
87    /// data must a validate ptr
88    pub unsafe fn write(&self, offset: u64, length: usize, data: *const u8) -> i32 {
89        let mut local_offset = 0;
90        let mut global_offset = offset;
91        let mut global_remaining = length;
92        for (i, vram) in self.vrams.iter().enumerate() {
93            let local_remaining = vram.remaining(global_offset);
94            if local_remaining.is_none() {
95                continue;
96            }
97            // compute local length to read/write
98            let local_length = global_remaining.min(local_remaining.unwrap());
99
100            let array = unsafe { std::slice::from_raw_parts(data.add(local_offset), local_length) };
101            if let Err(e) = vram.write(global_offset, array) {
102                log::error!(
103                    "Write error, device vram-{} offset {} size {}, code {}",
104                    i,
105                    global_offset,
106                    local_length,
107                    e
108                );
109                return -libc::EIO;
110            }
111
112            // re-compute rest to read/write
113            global_remaining -= local_length;
114            if global_remaining == 0 {
115                break;
116            }
117            local_offset += local_length;
118            global_offset += local_length as u64;
119        }
120        if global_remaining > 0 {
121            log::error!(
122                "Read error, offset {} size {}",
123                global_offset,
124                global_remaining
125            );
126            return -libc::EIO;
127        }
128        length as i32
129    }
130
131    pub fn size(&self) -> u64 {
132        self.size
133    }
134    pub fn blocks(&self) -> usize {
135        self.vrams.len()
136    }
137}
138
139impl<T: VBuffer> From<Vec<T>> for VMemory<T> {
140    fn from(vrams: Vec<T>) -> Self {
141        VMemory::new(vrams)
142    }
143}