Skip to content

Commit 710ace6

Browse files
authored
Merge pull request coconut-svsm#775 from luigix25/mmio_native
kernel/platform: Add mmio support for native platform
2 parents f7ea43a + e476ae6 commit 710ace6

5 files changed

Lines changed: 132 additions & 28 deletions

File tree

kernel/src/platform/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,19 +217,19 @@ pub trait SvsmPlatform: Sync {
217217
///
218218
/// # Safety
219219
///
220-
/// Caller must ensure that `pa` points to a properly aligned memory location and the
220+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
221221
/// memory accessed is part of a valid MMIO range.
222-
unsafe fn mmio_write(&self, _paddr: PhysAddr, _data: &[u8]) -> Result<(), SvsmError>;
222+
unsafe fn mmio_write(&self, vaddr: VirtAddr, data: &[u8]) -> Result<(), SvsmError>;
223223

224224
/// Perfrom a read from a memory-mapped IO area
225225
///
226226
/// # Safety
227227
///
228-
/// Caller must ensure that `paddr` points to a properly aligned memory location and the
228+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
229229
/// memory accessed is part of a valid MMIO range.
230230
unsafe fn mmio_read(
231231
&self,
232-
paddr: PhysAddr,
232+
vaddr: VirtAddr,
233233
data: &mut [MaybeUninit<u8>],
234234
) -> Result<(), SvsmError>;
235235
}

kernel/src/platform/native.rs

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,123 @@ impl SvsmPlatform for NativePlatform {
233233
Ok(())
234234
}
235235

236-
unsafe fn mmio_write(&self, _paddr: PhysAddr, _data: &[u8]) -> Result<(), SvsmError> {
237-
unimplemented!()
236+
/// Perform a write to a memory-mapped IO area
237+
///
238+
/// This function expects data to be 1, 2, 4 or 8 bytes long.
239+
///
240+
/// It is not possible to loop and write one byte at a time because mmio devices (e.g., those emulated by QEMU)
241+
/// expect certain registers to be written with a single operation. Using a generic on SvsmPlatform is
242+
/// not possible because it uses the dyn trait.
243+
///
244+
/// # Safety
245+
///
246+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
247+
/// memory accessed is part of a valid MMIO range.
248+
unsafe fn mmio_write(&self, vaddr: VirtAddr, data: &[u8]) -> Result<(), SvsmError> {
249+
match data.len() {
250+
1 => {
251+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
252+
unsafe {
253+
mmio_write_type::<u8>(vaddr, data);
254+
}
255+
}
256+
2 => {
257+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
258+
unsafe {
259+
mmio_write_type::<u16>(vaddr, data);
260+
}
261+
}
262+
4 => {
263+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
264+
unsafe {
265+
mmio_write_type::<u32>(vaddr, data);
266+
}
267+
}
268+
8 => {
269+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
270+
unsafe {
271+
mmio_write_type::<u64>(vaddr, data);
272+
}
273+
}
274+
_ => return Err(SvsmError::InvalidBytes),
275+
};
276+
277+
Ok(())
238278
}
239279

280+
/// Perform a read from a memory-mapped IO area
281+
///
282+
/// This function expects reads to be 1, 2, 4 or 8 bytes long.
283+
///
284+
/// It is not possible to loop and read one byte at a time because mmio devices (e.g., those emulated by QEMU)
285+
/// expect certain registers to be read with a single operation. Using a generic on SvsmPlatform is
286+
/// not possible because it uses the dyn trait.
287+
///
288+
/// # Safety
289+
///
290+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
291+
/// memory accessed is part of a valid MMIO range.
240292
unsafe fn mmio_read(
241293
&self,
242-
_paddr: PhysAddr,
243-
_data: &mut [MaybeUninit<u8>],
294+
vaddr: VirtAddr,
295+
data: &mut [MaybeUninit<u8>],
244296
) -> Result<(), SvsmError> {
245-
unimplemented!()
297+
match data.len() {
298+
1 => {
299+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
300+
unsafe {
301+
mmio_read_type::<u8>(vaddr, data);
302+
}
303+
}
304+
2 => {
305+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
306+
unsafe {
307+
mmio_read_type::<u16>(vaddr, data);
308+
}
309+
}
310+
4 => {
311+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
312+
unsafe {
313+
mmio_read_type::<u32>(vaddr, data);
314+
}
315+
}
316+
8 => {
317+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
318+
unsafe {
319+
mmio_read_type::<u64>(vaddr, data);
320+
}
321+
}
322+
_ => return Err(SvsmError::InvalidBytes),
323+
};
324+
325+
Ok(())
246326
}
247327
}
328+
329+
unsafe fn mmio_write_type<T: Copy>(vaddr: VirtAddr, data: &[u8]) {
330+
let data_ptr = data.as_ptr().cast::<T>();
331+
let ptr = vaddr.as_mut_ptr::<T>();
332+
333+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
334+
unsafe {
335+
if data_ptr.is_aligned() {
336+
ptr.write_volatile(data_ptr.read());
337+
} else {
338+
ptr.write_volatile(data_ptr.read_unaligned());
339+
}
340+
};
341+
}
342+
343+
unsafe fn mmio_read_type<T>(vaddr: VirtAddr, data: &mut [MaybeUninit<u8>]) {
344+
let data_ptr = data.as_mut_ptr().cast::<T>();
345+
let ptr = vaddr.as_mut_ptr::<T>();
346+
347+
// SAFETY: We are trusting the caller to ensure validity of `vaddr`.
348+
unsafe {
349+
if data_ptr.is_aligned() {
350+
data_ptr.write(ptr.read_volatile());
351+
} else {
352+
data_ptr.write_unaligned(ptr.read_volatile());
353+
}
354+
};
355+
}

kernel/src/platform/snp.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,9 +381,11 @@ impl SvsmPlatform for SnpPlatform {
381381
///
382382
/// # Safety
383383
///
384-
/// Caller must ensure that `paddr` points to a properly aligned memory location and the
384+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
385385
/// memory accessed is part of a valid MMIO range.
386-
unsafe fn mmio_write(&self, paddr: PhysAddr, data: &[u8]) -> Result<(), SvsmError> {
386+
unsafe fn mmio_write(&self, vaddr: VirtAddr, data: &[u8]) -> Result<(), SvsmError> {
387+
let paddr = this_cpu().get_pgtable().phys_addr(vaddr)?;
388+
387389
// SAFETY: We are trusting the caller to ensure validity of `paddr` and alignment of data.
388390
unsafe { crate::cpu::percpu::current_ghcb().mmio_write(paddr, data) }
389391
}
@@ -392,13 +394,14 @@ impl SvsmPlatform for SnpPlatform {
392394
///
393395
/// # Safety
394396
///
395-
/// Caller must ensure that `paddr` points to a properly aligned memory location and the
397+
/// Caller must ensure that `vaddr` points to a properly aligned memory location and the
396398
/// memory accessed is part of a valid MMIO range.
397399
unsafe fn mmio_read(
398400
&self,
399-
paddr: PhysAddr,
401+
vaddr: VirtAddr,
400402
data: &mut [MaybeUninit<u8>],
401403
) -> Result<(), SvsmError> {
404+
let paddr = this_cpu().get_pgtable().phys_addr(vaddr)?;
402405
// SAFETY: We are trusting the caller to ensure validity of `paddr` and alignment of data.
403406
unsafe { crate::cpu::percpu::current_ghcb().mmio_read(paddr, data) }
404407
}

kernel/src/platform/tdp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,13 +280,13 @@ impl SvsmPlatform for TdpPlatform {
280280
Ok(())
281281
}
282282

283-
unsafe fn mmio_write(&self, _paddr: PhysAddr, _data: &[u8]) -> Result<(), SvsmError> {
283+
unsafe fn mmio_write(&self, _vaddr: VirtAddr, _data: &[u8]) -> Result<(), SvsmError> {
284284
unimplemented!()
285285
}
286286

287287
unsafe fn mmio_read(
288288
&self,
289-
_paddr: PhysAddr,
289+
_vaddr: VirtAddr,
290290
_data: &mut [MaybeUninit<u8>],
291291
) -> Result<(), SvsmError> {
292292
unimplemented!()

kernel/src/virtio/hal.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use zerocopy::{FromBytes, Immutable, IntoBytes};
1616

1717
use crate::{
1818
address::{PhysAddr, VirtAddr},
19-
cpu::percpu::this_cpu,
2019
mm::{page_visibility::*, *},
2120
};
2221

@@ -198,11 +197,6 @@ unsafe impl virtio_drivers::Hal for SvsmHal {
198197
///
199198
/// `src` must be properly aligned and reside at a readable memory address.
200199
unsafe fn mmio_read<T: FromBytes + Immutable>(src: &T) -> T {
201-
let paddr = this_cpu()
202-
.get_pgtable()
203-
.phys_addr(VirtAddr::from(addr_of!(*src)))
204-
.unwrap();
205-
206200
let mut b = MaybeUninit::<T>::uninit();
207201
// SAFETY: We are trusting the caller (the virtio driver) to ensure `src` is a valid MMIO
208202
// address and that it is aligned properly. If SVSM_PLATFORM.mmio_read() doesn't fail
@@ -215,7 +209,9 @@ unsafe impl virtio_drivers::Hal for SvsmHal {
215209
b.as_mut_ptr().cast::<MaybeUninit<u8>>(),
216210
size_of::<T>(),
217211
);
218-
SVSM_PLATFORM.mmio_read(paddr, b_slice).unwrap();
212+
SVSM_PLATFORM
213+
.mmio_read(VirtAddr::from(addr_of!(*src)), b_slice)
214+
.unwrap();
219215
b.assume_init()
220216
}
221217
}
@@ -229,14 +225,11 @@ unsafe impl virtio_drivers::Hal for SvsmHal {
229225
///
230226
/// `dst` must be properly aligned and reside at a writable memory address.
231227
unsafe fn mmio_write<T: IntoBytes + Immutable>(dst: &mut T, v: T) {
232-
let paddr = this_cpu()
233-
.get_pgtable()
234-
.phys_addr(VirtAddr::from(addr_of!(*dst)))
235-
.unwrap();
236-
237228
// SAFETY: We are trusting the caller (the virtio driver) to ensure validity of `paddr` and alignment of data.
238229
unsafe {
239-
SVSM_PLATFORM.mmio_write(paddr, v.as_bytes()).unwrap();
230+
SVSM_PLATFORM
231+
.mmio_write(VirtAddr::from(addr_of!(*dst)), v.as_bytes())
232+
.unwrap();
240233
}
241234
}
242235
}

0 commit comments

Comments
 (0)