mapped.rs67.21%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
use std::cell::UnsafeCell;16
#[cfg(target_os = "linux")]17
use std::ffi::CStr;18
use std::fmt::Debug;19
use std::fs::File;20
use std::io::{IoSlice, IoSliceMut, Read, Write};21
use std::mem::{align_of, size_of};22
#[cfg(target_os = "linux")]23
use std::os::fd::FromRawFd;24
use std::os::fd::{AsFd, AsRawFd, BorrowedFd};25
use std::ptr::{NonNull, null_mut};26
use std::sync::Arc;27
28
#[cfg(target_os = "linux")]29
use libc::{MADV_HUGEPAGE, MFD_CLOEXEC};30
use libc::{31
MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, MS_ASYNC, PROT_READ, PROT_WRITE, c_void,32
madvise, mmap, msync, munmap,33
};34
use parking_lot::{RwLock, RwLockReadGuard};35
use snafu::ResultExt;36
use zerocopy::{FromBytes, Immutable, IntoBytes};37
38
use crate::ffi;39
use crate::mem::addressable::{Addressable, SlotBackend};40
use crate::mem::{Error, Result, error};41
42
#[derive(Debug)]43
struct MemPages {44
addr: NonNull<c_void>,45
len: usize,46
fd: Option<(File, u64)>,47
}48
49
unsafe impl Send for MemPages {}50
unsafe impl Sync for MemPages {}51
52
impl Drop for MemPages {53
fn drop(&mut self) {78x54
let ret = unsafe { munmap(self.addr.as_ptr(), self.len) };78x55
if ret != 0 {78x56
log::error!("munmap({:p}, {:x}) = {:x}", self.addr, self.len, ret);57
} else {58
log::info!("munmap({:p}, {:x}) = {:x}, done", self.addr, self.len, ret);78x59
}60
}78x61
}62
// ArcMemPages uses Arc to manage the underlying memory and caches63
// the address and size on the stack. Compared with using Arc<MemPages>,64
// it avoids a memory load when a caller tries to read/write the pages.65
// TODO: is it really necessary?66
#[derive(Debug, Clone)]67
pub struct ArcMemPages {68
addr: usize,69
size: usize,70
_inner: Arc<MemPages>,71
}72
73
impl SlotBackend for ArcMemPages {74
fn size(&self) -> u64 {2085x75
self.size as u642085x76
}2085x77
}78
79
impl ArcMemPages {80
pub fn addr(&self) -> usize {81
self.addr82
}83
84
pub fn size(&self) -> u64 {85
self.size as u6486
}87
88
pub fn fd(&self) -> Option<(BorrowedFd<'_>, u64)> {89
self._inner90
.fd91
.as_ref()92
.map(|(f, offset)| (f.as_fd(), *offset))93
}94
95
pub fn sync(&self) -> Result<()> {96
ffi!(unsafe { msync(self.addr as *mut _, self.size, MS_ASYNC) })?;97
Ok(())98
}99
100
#[cfg(target_os = "linux")]101
pub fn madvise_hugepage(&self) -> Result<()> {102
ffi!(unsafe { madvise(self.addr as *mut _, self.size, MADV_HUGEPAGE) })?;103
Ok(())104
}105
106
fn from_raw(addr: *mut c_void, len: usize, fd: Option<(File, u64)>) -> Self {78x107
let addr = NonNull::new(addr).expect("address from mmap() should not be null");78x108
ArcMemPages {78x109
addr: addr.as_ptr() as usize,78x110
size: len,78x111
_inner: Arc::new(MemPages { addr, len, fd }),78x112
}78x113
}78x114
115
pub fn from_file(file: File, offset: i64, len: usize, prot: i32) -> Result<Self> {116
let addr = ffi!(117
unsafe { mmap(null_mut(), len, prot, MAP_SHARED, file.as_raw_fd(), offset) },118
MAP_FAILED119
)?;120
Ok(Self::from_raw(addr, len, Some((file, offset as u64))))121
}122
123
#[cfg(target_os = "linux")]124
pub fn from_memfd(name: &CStr, size: usize, prot: Option<i32>) -> Result<Self> {125
let fd = ffi!(unsafe { libc::memfd_create(name.as_ptr(), MFD_CLOEXEC) })?;126
let prot = prot.unwrap_or(PROT_WRITE | PROT_READ);127
let addr = ffi!(128
unsafe { mmap(null_mut(), size, prot, MAP_SHARED, fd, 0) },129
MAP_FAILED130
)?;131
let file = unsafe { File::from_raw_fd(fd) };132
file.set_len(size as _)?;133
Ok(Self::from_raw(addr, size, Some((file, 0))))134
}135
136
pub fn from_anonymous(size: usize, prot: Option<i32>, flags: Option<i32>) -> Result<Self> {78x137
let prot = prot.unwrap_or(PROT_WRITE | PROT_READ);78x138
let flags = flags.unwrap_or(MAP_PRIVATE) | MAP_ANONYMOUS;78x139
let addr = ffi!(78x140
unsafe { mmap(null_mut(), size, prot, flags, -1, 0) },78x141
MAP_FAILED142
)?;143
Ok(Self::from_raw(addr, size, None))78x144
}78x145
146
/// Given offset and len, return the host virtual address and len;147
/// len might be truncated.148
fn get_valid_range(&self, offset: usize, len: usize) -> Result<(usize, usize)> {2388x149
let end = offset.wrapping_add(len).wrapping_sub(1);2388x150
if offset >= self.size || end < offset {2388x151
return error::ExceedsLimit {152
addr: offset as u64,153
size: len as u64,154
}155
.fail();156
}2388x157
let valid_len = std::cmp::min(self.size - offset, len);2388x158
Ok((self.addr + offset, valid_len))2388x159
}2388x160
161
pub fn as_slice_mut(&mut self) -> &mut [u8] {162
unsafe { std::slice::from_raw_parts_mut(self.addr as *mut u8, self.size) }163
}164
165
pub fn as_slice(&self) -> &[u8] {166
unsafe { std::slice::from_raw_parts(self.addr as *const u8, self.size) }167
}168
169
/// Given offset and len, return a slice, len might be truncated.170
fn get_partial_slice(&self, offset: usize, len: usize) -> Result<&[u8], Error> {1002x171
let (addr, len) = self.get_valid_range(offset, len)?;1002x172
Ok(unsafe { std::slice::from_raw_parts(addr as *const u8, len) })1002x173
}1002x174
175
/// Given offset and len, return a mutable slice, len might be truncated.176
#[allow(clippy::mut_from_ref)]177
fn get_partial_slice_mut(&self, offset: usize, len: usize) -> Result<&mut [u8], Error> {1386x178
let (addr, len) = self.get_valid_range(offset, len)?;1386x179
Ok(unsafe { std::slice::from_raw_parts_mut(addr as *mut u8, len) })1386x180
}1386x181
}182
183
#[derive(Debug)]184
pub struct Ram {185
inner: Addressable<ArcMemPages>,186
}187
188
#[derive(Debug)]189
pub struct RamBus {190
ram: RwLock<Ram>,191
}192
193
struct Iter<'m> {194
ram: &'m Ram,195
gpa: u64,196
remain: u64,197
}198
199
impl<'m> Iterator for Iter<'m> {200
type Item = Result<&'m [u8]>;201
202
fn next(&mut self) -> Option<Self::Item> {1224x203
if self.remain == 0 {1224x204
return None;384x205
}840x206
let r = self.ram.get_partial_slice(self.gpa, self.remain);840x207
if let Ok(s) = r {840x208
self.gpa += s.len() as u64;747x209
self.remain -= s.len() as u64;747x210
}747x211
Some(r)840x212
}1224x213
}214
215
struct IterMut<'m> {216
ram: &'m Ram,217
gpa: u64,218
remain: u64,219
}220
221
impl<'m> Iterator for IterMut<'m> {222
type Item = Result<&'m mut [u8]>;223
224
fn next(&mut self) -> Option<Self::Item> {1158x225
if self.remain == 0 {1158x226
return None;345x227
}813x228
let r = self.ram.get_partial_slice_mut(self.gpa, self.remain);813x229
if let Ok(ref s) = r {813x230
self.gpa += s.len() as u64;720x231
self.remain -= s.len() as u64;720x232
}720x233
Some(r)813x234
}1158x235
}236
237
impl Ram {238
fn slice_iter(&self, gpa: u64, len: u64) -> Iter<'_> {477x239
Iter {477x240
ram: self,477x241
gpa,477x242
remain: len,477x243
}477x244
}477x245
246
fn slice_iter_mut(&self, gpa: u64, len: u64) -> IterMut<'_> {438x247
IterMut {438x248
ram: self,438x249
gpa,438x250
remain: len,438x251
}438x252
}438x253
254
fn get_partial_slice(&self, gpa: u64, len: u64) -> Result<&[u8]> {1095x255
let Some((start, user_mem)) = self.inner.search(gpa) else {1095x256
return error::NotMapped { addr: gpa }.fail();93x257
};258
user_mem.get_partial_slice((gpa - start) as usize, len as usize)1002x259
}1095x260
261
fn get_partial_slice_mut(&self, gpa: u64, len: u64) -> Result<&mut [u8]> {1479x262
let Some((start, user_mem)) = self.inner.search(gpa) else {1479x263
return error::NotMapped { addr: gpa }.fail();93x264
};265
user_mem.get_partial_slice_mut((gpa - start) as usize, len as usize)1386x266
}1479x267
268
pub fn get_slice<T>(&self, gpa: u64, len: u64) -> Result<&[UnsafeCell<T>], Error> {269
let total_len = len * size_of::<T>() as u64;270
let host_ref = self.get_partial_slice(gpa, total_len)?;271
let ptr = host_ref.as_ptr() as *const UnsafeCell<T>;272
if host_ref.len() as u64 != total_len {273
error::NotContinuous {274
addr: gpa,275
size: total_len,276
}277
.fail()278
} else if !ptr.is_aligned() {279
error::NotAligned {280
addr: ptr as u64,281
align: align_of::<T>(),282
}283
.fail()284
} else {285
Ok(unsafe { &*core::ptr::slice_from_raw_parts(ptr, len as usize) })286
}287
}288
289
pub fn get_ptr<T>(&self, gpa: u64) -> Result<*mut T, Error> {390x290
let host_ref = self.get_partial_slice_mut(gpa, size_of::<T>() as u64)?;390x291
let ptr = host_ref.as_mut_ptr();390x292
if host_ref.len() != size_of::<T>() {390x293
error::NotContinuous {294
addr: gpa,295
size: size_of::<T>() as u64,296
}297
.fail()298
} else if !ptr.is_aligned() {390x299
error::NotAligned {300
addr: ptr as u64,301
align: align_of::<T>(),302
}303
.fail()304
} else {305
Ok(ptr as *mut T)390x306
}307
}390x308
309
pub fn read(&self, gpa: u64, buf: &mut [u8]) -> Result<()> {255x310
let host_ref = self.get_partial_slice(gpa, buf.len() as u64)?;255x311
if host_ref.len() == buf.len() {255x312
buf.copy_from_slice(host_ref);69x313
} else {69x314
let mut cur = 0;186x315
for r in self.slice_iter(gpa, buf.len() as u64) {372x316
let s = r?;372x317
let s_len = s.len();279x318
buf[cur..(cur + s_len)].copy_from_slice(s);279x319
cur += s_len;279x320
}321
}322
Ok(())162x323
}255x324
325
pub fn read_t<T>(&self, gpa: u64) -> Result<T>225x326
where225x327
T: FromBytes + IntoBytes,225x328
{329
let mut v = T::new_zeroed();225x330
self.read(gpa, v.as_mut_bytes())?;225x331
Ok(v)132x332
}225x333
334
pub fn write(&self, gpa: u64, buf: &[u8]) -> Result<()> {276x335
let len = buf.len() as u64;276x336
let host_ref = self.get_partial_slice_mut(gpa, len)?;276x337
if host_ref.len() == buf.len() {276x338
host_ref.copy_from_slice(buf);90x339
Ok(())90x340
} else {341
let mut cur = 0;186x342
for r in self.slice_iter_mut(gpa, len) {372x343
let s = r?;372x344
let s_len = s.len();279x345
s.copy_from_slice(&buf[cur..(cur + s_len)]);279x346
cur += s_len;279x347
}348
Ok(())93x349
}350
}276x351
352
pub fn write_t<T>(&self, gpa: u64, val: &T) -> Result<(), Error>225x353
where225x354
T: IntoBytes + Immutable,225x355
{356
self.write(gpa, val.as_bytes())225x357
}225x358
359
pub fn translate(&self, gpa: u64) -> Result<*const u8> {360
let s = self.get_partial_slice(gpa, 1)?;361
Ok(s.as_ptr())362
}363
364
pub fn translate_iov<'a>(&'a self, iov: &[(u64, u64)]) -> Result<Vec<IoSlice<'a>>> {90x365
let mut slices = vec![];90x366
for (gpa, len) in iov {90x367
for r in self.slice_iter(*gpa, *len) {87x368
slices.push(IoSlice::new(r?));72x369
}370
}371
Ok(slices)90x372
}90x373
374
pub fn translate_iov_mut<'a>(&'a self, iov: &[(u64, u64)]) -> Result<Vec<IoSliceMut<'a>>> {87x375
let mut slices = vec![];87x376
for (gpa, len) in iov {87x377
for r in self.slice_iter_mut(*gpa, *len) {48x378
slices.push(IoSliceMut::new(r?));45x379
}380
}381
Ok(slices)87x382
}87x383
384
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (u64, &ArcMemPages)> {385
self.inner.iter()386
}387
388
pub fn madvise(&self, gpa: u64, size: u64, advice: i32) -> Result<()> {389
for r in self.slice_iter_mut(gpa, size) {390
let s = r?;391
ffi!(unsafe { madvise(s.as_mut_ptr() as _, s.len(), advice) })?;392
}393
Ok(())394
}395
}396
397
impl Default for RamBus {398
fn default() -> Self {399
Self::new()400
}401
}402
403
impl RamBus {404
pub fn lock_layout(&self) -> RwLockReadGuard<'_, Ram> {81x405
self.ram.read()81x406
}81x407
408
pub fn new() -> Self {81x409
Self {81x410
ram: RwLock::new(Ram {81x411
inner: Addressable::default(),81x412
}),81x413
}81x414
}81x415
416
pub(crate) fn add(&self, gpa: u64, user_mem: ArcMemPages) -> Result<(), Error> {78x417
let mut ram = self.ram.write();78x418
ram.inner.add(gpa, user_mem)?;78x419
Ok(())78x420
}78x421
422
pub(crate) fn remove(&self, gpa: u64) -> Result<ArcMemPages, Error> {3x423
let mut ram = self.ram.write();3x424
ram.inner.remove(gpa)3x425
}3x426
427
pub fn read(&self, gpa: u64, buf: &mut [u8]) -> Result<()> {428
let ram = self.ram.read();429
ram.read(gpa, buf)430
}431
432
pub fn write(&self, gpa: u64, buf: &[u8]) -> Result<()> {433
let ram = self.ram.read();434
ram.write(gpa, buf)435
}436
437
pub fn read_t<T>(&self, gpa: u64) -> Result<T, Error>225x438
where225x439
T: FromBytes + IntoBytes,225x440
{441
let ram = self.ram.read();225x442
ram.read_t(gpa)225x443
}225x444
445
pub fn write_t<T>(&self, gpa: u64, val: &T) -> Result<(), Error>225x446
where225x447
T: IntoBytes + Immutable,225x448
{449
let ram = self.ram.read();225x450
ram.write_t(gpa, val)225x451
}225x452
453
pub fn read_range(&self, gpa: u64, len: u64, dst: &mut impl Write) -> Result<()> {195x454
let ram = self.ram.read();195x455
for r in ram.slice_iter(gpa, len) {384x456
dst.write_all(r?).context(error::Write)?;384x457
}458
Ok(())195x459
}195x460
461
pub fn write_range(&self, gpa: u64, len: u64, mut src: impl Read) -> Result<()> {195x462
let ram = self.ram.read();195x463
for r in ram.slice_iter_mut(gpa, len) {384x464
src.read_exact(r?).context(error::Read)?;384x465
}466
Ok(())195x467
}195x468
469
pub fn read_vectored<T, F>(&self, bufs: &[(u64, u64)], callback: F) -> Result<T, Error>3x470
where3x471
F: FnOnce(&[IoSlice<'_>]) -> T,3x472
{473
let ram = self.ram.read();3x474
let mut iov = vec![];3x475
for (gpa, len) in bufs {9x476
for r in ram.slice_iter(*gpa, *len) {12x477
iov.push(IoSlice::new(r?));12x478
}479
}480
Ok(callback(&iov))3x481
}3x482
483
pub fn write_vectored<T, F>(&self, bufs: &[(u64, u64)], callback: F) -> Result<T, Error>3x484
where3x485
F: FnOnce(&mut [IoSliceMut<'_>]) -> T,3x486
{487
let ram = self.ram.read();3x488
let mut iov = vec![];3x489
for (gpa, len) in bufs {9x490
for r in ram.slice_iter_mut(*gpa, *len) {12x491
iov.push(IoSliceMut::new(r?));12x492
}493
}494
Ok(callback(&mut iov))3x495
}3x496
}497
498
#[cfg(test)]499
#[path = "mapped_test.rs"]500
mod tests;501