mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 04:26:38 +00:00
write_all_at()/read_exact_at() fail to access pmc_mux through /dev/mem. while devmem2 tool success to access them through /dev/mem, so this commit reference devmem2 implementation and use mmap to access direct mmio. BUG=b:199354528 TEST=Apply https://chromium-review.googlesource.com/c/chromiumos/platform/initramfs/+/3194150 , then verify platform device (like typec) function in ManaTEE CrOS Change-Id: Id69c44444e2dc1ef6d40cb7b36febda38848d4f0 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3259931 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
199 lines
5.6 KiB
Rust
199 lines
5.6 KiB
Rust
// Copyright 2021 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
use crate::{BusAccessInfo, BusDevice, BusDeviceSync, BusRange};
|
|
use base::{
|
|
error, pagesize, round_up_to_page_size, MemoryMapping, MemoryMappingBuilder, Protection,
|
|
};
|
|
use std::fs::{File, OpenOptions};
|
|
use std::io;
|
|
use std::os::unix::fs::OpenOptionsExt;
|
|
use std::os::unix::prelude::FileExt;
|
|
use std::path::Path;
|
|
use std::sync::Mutex;
|
|
|
|
pub struct DirectIo {
|
|
dev: Mutex<File>,
|
|
read_only: bool,
|
|
}
|
|
|
|
impl DirectIo {
|
|
/// Create simple direct I/O access device.
|
|
pub fn new(path: &Path, read_only: bool) -> Result<Self, io::Error> {
|
|
let dev = OpenOptions::new().read(true).write(!read_only).open(path)?;
|
|
Ok(DirectIo {
|
|
dev: Mutex::new(dev),
|
|
read_only,
|
|
})
|
|
}
|
|
|
|
fn iowr(&self, port: u64, data: &[u8]) {
|
|
if !self.read_only {
|
|
if let Ok(ref mut dev) = self.dev.lock() {
|
|
let _ = dev.write_all_at(data, port);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn iord(&self, port: u64, data: &mut [u8]) {
|
|
if let Ok(ref mut dev) = self.dev.lock() {
|
|
let _ = dev.read_exact_at(data, port);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BusDevice for DirectIo {
|
|
fn debug_label(&self) -> String {
|
|
"direct-io".to_string()
|
|
}
|
|
|
|
/// Reads at `offset` from this device
|
|
fn read(&mut self, ai: BusAccessInfo, data: &mut [u8]) {
|
|
self.iord(ai.address, data);
|
|
}
|
|
|
|
/// Writes at `offset` into this device
|
|
fn write(&mut self, ai: BusAccessInfo, data: &[u8]) {
|
|
self.iowr(ai.address, data);
|
|
}
|
|
}
|
|
|
|
impl BusDeviceSync for DirectIo {
|
|
/// Reads at `offset` from this device
|
|
fn read(&self, ai: BusAccessInfo, data: &mut [u8]) {
|
|
self.iord(ai.address, data);
|
|
}
|
|
|
|
/// Writes at `offset` into this device
|
|
fn write(&self, ai: BusAccessInfo, data: &[u8]) {
|
|
self.iowr(ai.address, data);
|
|
}
|
|
}
|
|
|
|
pub struct DirectMmio {
|
|
dev: Mutex<Vec<(BusRange, MemoryMapping)>>,
|
|
read_only: bool,
|
|
}
|
|
|
|
impl DirectMmio {
|
|
/// Create simple direct mmio access device.
|
|
pub fn new(path: &Path, read_only: bool, ranges: Vec<BusRange>) -> Result<Self, io::Error> {
|
|
let dev = OpenOptions::new()
|
|
.read(true)
|
|
.write(!read_only)
|
|
.custom_flags(libc::O_SYNC)
|
|
.open(path)?;
|
|
let mut mmap_info = Vec::new();
|
|
|
|
let protection = if read_only {
|
|
Protection::read()
|
|
} else {
|
|
Protection::read_write()
|
|
};
|
|
|
|
for range in &ranges {
|
|
// set to the page start
|
|
let start = range.base & (!((pagesize() - 1) as u64));
|
|
// set to the next page of the end address
|
|
let end = round_up_to_page_size((range.base + range.len) as usize);
|
|
let len = end - start as usize;
|
|
let mmap = match MemoryMappingBuilder::new(len)
|
|
.from_file(&dev)
|
|
.offset(start)
|
|
.protection(protection)
|
|
.build()
|
|
{
|
|
Ok(m) => m,
|
|
Err(e) => {
|
|
error!(
|
|
"failed to create mmap for mmio: {:x} ~ {:x}, error: {}",
|
|
range.base,
|
|
range.base + range.len,
|
|
e
|
|
);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
mmap_info.push((*range, mmap));
|
|
}
|
|
|
|
Ok(DirectMmio {
|
|
dev: Mutex::new(mmap_info),
|
|
read_only,
|
|
})
|
|
}
|
|
|
|
fn iowr(&self, ai: BusAccessInfo, data: &[u8]) {
|
|
if self.read_only {
|
|
return;
|
|
}
|
|
|
|
let dev = match self.dev.lock() {
|
|
Ok(d) => d,
|
|
Err(_) => return,
|
|
};
|
|
|
|
for (range, mmap) in dev.iter() {
|
|
if !range.contains(ai.address) || !range.contains(ai.address + data.len() as u64) {
|
|
continue;
|
|
}
|
|
|
|
let page_mask = (pagesize() - 1) as u64;
|
|
let offset = (range.base & page_mask) + ai.offset;
|
|
if let Err(e) = mmap.write_slice(data, offset as usize) {
|
|
error!("write mmio {:x} error, {}", ai.address, e);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
fn iord(&self, ai: BusAccessInfo, data: &mut [u8]) {
|
|
let dev = match self.dev.lock() {
|
|
Ok(d) => d,
|
|
Err(_) => return,
|
|
};
|
|
|
|
for (range, mmap) in dev.iter() {
|
|
if !range.contains(ai.address) || !range.contains(ai.address + data.len() as u64) {
|
|
continue;
|
|
}
|
|
|
|
let page_mask = (pagesize() - 1) as u64;
|
|
let offset = (range.base & page_mask) + ai.offset;
|
|
if let Err(e) = mmap.read_slice(data, offset as usize) {
|
|
error!("read mmio {:x} error {}", ai.address, e);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BusDevice for DirectMmio {
|
|
fn debug_label(&self) -> String {
|
|
"direct-mmio".to_string()
|
|
}
|
|
|
|
/// Reads at `offset` from this device
|
|
fn read(&mut self, ai: BusAccessInfo, data: &mut [u8]) {
|
|
self.iord(ai, data);
|
|
}
|
|
|
|
/// Writes at `offset` into this device
|
|
fn write(&mut self, ai: BusAccessInfo, data: &[u8]) {
|
|
self.iowr(ai, data);
|
|
}
|
|
}
|
|
|
|
impl BusDeviceSync for DirectMmio {
|
|
/// Reads at `offset` from this device
|
|
fn read(&self, ai: BusAccessInfo, data: &mut [u8]) {
|
|
self.iord(ai, data);
|
|
}
|
|
|
|
/// Writes at `offset` into this device
|
|
fn write(&self, ai: BusAccessInfo, data: &[u8]) {
|
|
self.iowr(ai, data);
|
|
}
|
|
}
|