diff --git a/kernel-rs/Cargo.lock b/kernel-rs/Cargo.lock index 4b601771..139d957f 100644 --- a/kernel-rs/Cargo.lock +++ b/kernel-rs/Cargo.lock @@ -31,6 +31,12 @@ name = "bitmaps" version = "3.0.0" source = "git+https://github.com/jeehoonkang/bitmaps.git?branch=rv6#fa70c4040e625c6e70b3fa0c87caf28594fbbbce" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "const-zero" version = "0.1.0" @@ -166,6 +172,7 @@ dependencies = [ "scopeguard", "spin", "static_assertions", + "zerocopy", ] [[package]] @@ -200,8 +207,41 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "zerocopy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0af017aca1fa6181f5dd7a802456fe6f7666ecdcc18d0910431f0fc89d474e51" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] diff --git a/kernel-rs/Cargo.toml b/kernel-rs/Cargo.toml index 66c07775..7a723efb 100644 --- a/kernel-rs/Cargo.toml +++ b/kernel-rs/Cargo.toml @@ -34,6 +34,7 @@ pin-project = "1.0.7" scopeguard = { version = "1.1.0", default-features = false } spin = "0.9.0" static_assertions = "1.1.0" +zerocopy = "0.5.0" # Compiler options for sysroot packages. # Cargo currently warns following packages are not dependencies. diff --git a/kernel-rs/src/arch/memlayout.rs b/kernel-rs/src/arch/memlayout.rs index 9ff30614..7ad7b56b 100644 --- a/kernel-rs/src/arch/memlayout.rs +++ b/kernel-rs/src/arch/memlayout.rs @@ -15,6 +15,10 @@ //! 80000000 -- entry.S, then kernel text and data //! end -- start of kernel page allocation area //! PHYSTOP -- end RAM used by the kernel + +// Dead code is allowed in this file because not all components are used in the kernel. +#![allow(dead_code)] + use crate::arch::addr::{MAXVA, PGSIZE}; /// SiFive Test Finisher. (virt device only) diff --git a/kernel-rs/src/arch/mod.rs b/kernel-rs/src/arch/mod.rs index 6ba77d64..eb3b7b6d 100644 --- a/kernel-rs/src/arch/mod.rs +++ b/kernel-rs/src/arch/mod.rs @@ -1,8 +1,5 @@ //! Architecture-dependent code. -// TODO(https://github.com/kaist-cp/rv6/issues/120) -#![allow(dead_code)] - pub mod addr; pub mod memlayout; pub mod plic; diff --git a/kernel-rs/src/arch/riscv.rs b/kernel-rs/src/arch/riscv.rs index 28d35de4..25786e47 100644 --- a/kernel-rs/src/arch/riscv.rs +++ b/kernel-rs/src/arch/riscv.rs @@ -1,3 +1,8 @@ +//! RISC-V instructions. + +// Dead code is allowed in this file because not all components are used in the kernel. +#![allow(dead_code)] + use bitflags::bitflags; /// Which hart (core) is this? diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index 5b19a164..cc66ad77 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -309,7 +309,7 @@ impl fmt::Write for Printer { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.bytes() { // TODO(https://github.com/kaist-cp/rv6/issues/267): remove kernel_builder() - let kernel = kernel_builder(); + let kernel = unsafe { kernel_builder() }; kernel.console.putc_spin(c, &kernel); } Ok(()) diff --git a/kernel-rs/src/exec.rs b/kernel-rs/src/exec.rs index f81e25bc..aadc2cd9 100644 --- a/kernel-rs/src/exec.rs +++ b/kernel-rs/src/exec.rs @@ -4,6 +4,7 @@ use core::{cmp, mem}; use bitflags::bitflags; use itertools::*; +use zerocopy::{AsBytes, FromBytes}; use crate::{ arch::addr::{pgroundup, PAddr, PGSIZE}, @@ -26,6 +27,7 @@ const ELF_PROG_LOAD: u32 = 1; // which should follow C(=machine) representation // https://github.com/kaist-cp/rv6/issues/52 #[repr(C)] +#[derive(AsBytes, FromBytes)] struct ElfHdr { /// must equal ELF_MAGIC magic: u32, @@ -48,6 +50,7 @@ struct ElfHdr { bitflags! { /// Flag bits for ProgHdr flags #[repr(C)] + #[derive(AsBytes, FromBytes)] struct ProgFlags: u32 { const EXEC = 1; const WRITE = 2; @@ -67,6 +70,7 @@ impl Default for ProgFlags { // which should follow C(=machine) representation // https://github.com/kaist-cp/rv6/issues/52 #[repr(C)] +#[derive(AsBytes, FromBytes)] struct ProgHdr { typ: u32, flags: ProgFlags, @@ -106,9 +110,7 @@ impl KernelCtx<'_, '_> { // Check ELF header let mut elf: ElfHdr = Default::default(); - // SAFETY: ElfHdr can be safely transmuted to [u8; _], as it - // contains only integers, which do not have internal structures. - unsafe { ip.read_kernel(&mut elf, 0, self) }?; + ip.read_kernel(&mut elf, 0, self)?; if !elf.is_valid() { return Err(()); } @@ -123,9 +125,7 @@ impl KernelCtx<'_, '_> { let off = elf.phoff + i * mem::size_of::(); let mut ph: ProgHdr = Default::default(); - // SAFETY: ProgHdr can be safely transmuted to [u8; _], as it - // contains only integers, which do not have internal structures. - unsafe { ip.read_kernel(&mut ph, off as _, self) }?; + ip.read_kernel(&mut ph, off as _, self)?; if ph.is_prog_load() { if ph.memsz < ph.filesz || ph.vaddr % PGSIZE != 0 { return Err(()); diff --git a/kernel-rs/src/file.rs b/kernel-rs/src/file.rs index 61421a59..a474526f 100644 --- a/kernel-rs/src/file.rs +++ b/kernel-rs/src/file.rs @@ -220,7 +220,7 @@ impl ArenaObject for File { // TODO(https://github.com/kaist-cp/rv6/issues/290): The inode ip will // be dropped by drop(ip). Deallocation of an inode may cause disk write // operations, so we must begin a transaction here. - let _tx = kref.file_system.begin_transaction(); + let _tx = kref.fs().begin_transaction(); drop(ip); } _ => (), diff --git a/kernel-rs/src/fs/inode.rs b/kernel-rs/src/fs/inode.rs index eca42d36..761cde13 100644 --- a/kernel-rs/src/fs/inode.rs +++ b/kernel-rs/src/fs/inode.rs @@ -6,7 +6,7 @@ //! list of blocks holding the file's content. //! //! The inodes are laid out sequentially on disk at -//! kernel.file_system.superblock.startinode. Each inode has a number, indicating its +//! kernel.fs().superblock.startinode. Each inode has a number, indicating its //! position on the disk. //! //! The kernel keeps a table of in-use inodes in memory @@ -75,6 +75,7 @@ use core::{ }; use static_assertions::const_assert; +use zerocopy::{AsBytes, FromBytes}; use super::{FileName, Stat, IPB, MAXFILE, NDIRECT, NINDIRECT}; use crate::{ @@ -183,7 +184,8 @@ pub struct InodeGuard<'a> { pub inode: &'a Inode, } -#[derive(Default)] +#[repr(C)] +#[derive(Default, AsBytes, FromBytes)] pub struct Dirent { pub inum: u16, name: [u8; DIRSIZ], @@ -192,9 +194,7 @@ pub struct Dirent { impl Dirent { fn new(ip: &mut InodeGuard<'_>, off: u32, ctx: &KernelCtx<'_, '_>) -> Result { let mut dirent = Dirent::default(); - // SAFETY: Dirent can be safely transmuted to [u8; _], as it - // contains only u16 and u8's, which do not have internal structures. - unsafe { ip.read_kernel(&mut dirent, off, ctx) }?; + ip.read_kernel(&mut dirent, off, ctx)?; Ok(dirent) } @@ -324,9 +324,9 @@ impl InodeGuard<'_> { /// Must be called after every change to an ip->xxx field /// that lives on disk. pub fn update(&self, tx: &FsTransaction<'_>, ctx: &KernelCtx<'_, '_>) { - let mut bp = ctx.kernel().file_system.log.disk.read( + let mut bp = ctx.kernel().fs().log.disk.read( self.dev, - ctx.kernel().file_system.superblock().iblock(self.inum), + ctx.kernel().fs().superblock().iblock(self.inum), ctx, ); @@ -386,7 +386,7 @@ impl InodeGuard<'_> { if self.deref_inner().addr_indirect != 0 { let mut bp = ctx.kernel() - .file_system + .fs() .log .disk .read(dev, self.deref_inner().addr_indirect, ctx); @@ -409,22 +409,13 @@ impl InodeGuard<'_> { /// Copy data into `dst` from the content of inode at offset `off`. /// Return Ok(()) on success, Err(()) on failure. - /// - /// # Safety - /// - /// `T` can be safely `transmute`d to `[u8; size_of::()]`. - pub unsafe fn read_kernel( + pub fn read_kernel( &mut self, dst: &mut T, off: u32, ctx: &KernelCtx<'_, '_>, ) -> Result<(), ()> { - let bytes = self.read_bytes_kernel( - // SAFETY: the safety assumption of this method. - unsafe { core::slice::from_raw_parts_mut(dst as *mut _ as _, mem::size_of::()) }, - off, - ctx, - ); + let bytes = self.read_bytes_kernel(dst.as_bytes_mut(), off, ctx); if bytes == mem::size_of::() { Ok(()) } else { @@ -508,11 +499,12 @@ impl InodeGuard<'_> { } let mut tot: u32 = 0; while tot < n { - let bp = k.kernel().file_system.log.disk.read( - self.dev, - self.bmap(off as usize / BSIZE, &k), - &k, - ); + let bp = + k.kernel() + .fs() + .log + .disk + .read(self.dev, self.bmap(off as usize / BSIZE, &k), &k); let m = core::cmp::min(n - tot, BSIZE as u32 - off % BSIZE as u32); let begin = (off % BSIZE as u32) as usize; let end = begin + m as usize; @@ -525,21 +517,14 @@ impl InodeGuard<'_> { /// Copy data from `src` into the inode at offset `off`. /// Return Ok(()) on success, Err(()) on failure. - pub fn write_kernel( + pub fn write_kernel( &mut self, src: &T, off: u32, tx: &FsTransaction<'_>, ctx: &KernelCtx<'_, '_>, ) -> Result<(), ()> { - let bytes = self.write_bytes_kernel( - // SAFETY: src is a valid reference to T and - // u8 does not have any internal structure. - unsafe { core::slice::from_raw_parts(src as *const _ as _, mem::size_of::()) }, - off, - tx, - ctx, - )?; + let bytes = self.write_bytes_kernel(src.as_bytes(), off, tx, ctx)?; if bytes == mem::size_of::() { Ok(()) } else { @@ -631,7 +616,7 @@ impl InodeGuard<'_> { } let mut tot: u32 = 0; while tot < n { - let mut bp = k.kernel().file_system.log.disk.read( + let mut bp = k.kernel().fs().log.disk.read( self.dev, self.bmap_or_alloc(off as usize / BSIZE, tx, &k), &k, @@ -703,12 +688,7 @@ impl InodeGuard<'_> { self.deref_inner_mut().addr_indirect = indirect; } - let mut bp = ctx - .kernel() - .file_system - .log - .disk - .read(self.dev, indirect, ctx); + let mut bp = ctx.kernel().fs().log.disk.read(self.dev, indirect, ctx); let (prefix, data, _) = unsafe { bp.deref_inner_mut().data.align_to_mut::() }; debug_assert_eq!(prefix.len(), 0, "bmap: Buf data unaligned"); let mut addr = data[bn]; @@ -726,9 +706,8 @@ impl InodeGuard<'_> { pub fn is_dir_empty(&mut self, ctx: &KernelCtx<'_, '_>) -> bool { let mut de: Dirent = Default::default(); for off in (2 * DIRENT_SIZE as u32..self.deref_inner().size).step_by(DIRENT_SIZE) { - // SAFETY: Dirent can be safely transmuted to [u8; _], as it - // contains only u16 and u8's, which do not have internal structures. - unsafe { self.read_kernel(&mut de, off, ctx) }.expect("is_dir_empty: read_kernel"); + self.read_kernel(&mut de, off, ctx) + .expect("is_dir_empty: read_kernel"); if de.inum != 0 { return false; } @@ -771,9 +750,7 @@ impl ArenaObject for Inode { // resulting FsTransaction value is never used. Such transactions // can be found in finalize in file.rs, sys_chdir in sysfile.rs, // close_files in proc.rs, and exec in exec.rs. - let tx = mem::ManuallyDrop::new(FsTransaction { - fs: &kernel.file_system, - }); + let tx = mem::ManuallyDrop::new(FsTransaction { fs: &kernel.fs() }); // self->ref == 1 means no other process can have self locked, // so this acquiresleep() won't block (or deadlock). @@ -808,9 +785,9 @@ impl Inode { pub fn lock(&self, ctx: &KernelCtx<'_, '_>) -> InodeGuard<'_> { let mut guard = self.inner.lock(); if !guard.valid { - let mut bp = ctx.kernel().file_system.log.disk.read( + let mut bp = ctx.kernel().fs().log.disk.read( self.dev, - ctx.kernel().file_system.superblock().iblock(self.inum), + ctx.kernel().fs().superblock().iblock(self.inum), ctx, ); @@ -880,6 +857,7 @@ impl Inode { InodeType::Device { .. } => 3, }, nlink: inner.nlink, + _padding: 0, size: inner.size as usize, } } @@ -915,10 +893,10 @@ impl Itable { tx: &FsTransaction<'_>, ctx: &KernelCtx<'_, '_>, ) -> RcInode { - for inum in 1..ctx.kernel().file_system.superblock().ninodes { - let mut bp = ctx.kernel().file_system.log.disk.read( + for inum in 1..ctx.kernel().fs().superblock().ninodes { + let mut bp = ctx.kernel().fs().log.disk.read( dev, - ctx.kernel().file_system.superblock().iblock(inum), + ctx.kernel().fs().superblock().iblock(inum), ctx, ); diff --git a/kernel-rs/src/fs/mod.rs b/kernel-rs/src/fs/mod.rs index 815a6946..385d98ee 100644 --- a/kernel-rs/src/fs/mod.rs +++ b/kernel-rs/src/fs/mod.rs @@ -99,7 +99,7 @@ impl FsTransaction<'_> { /// commit()/write_log() will do the disk write. /// /// write() replaces write(); a typical use is: - /// bp = kernel.file_system.disk.read(...) + /// bp = kernel.fs().disk.read(...) /// modify bp->data[] /// write(bp) fn write(&self, b: Buf) { diff --git a/kernel-rs/src/fs/stat.rs b/kernel-rs/src/fs/stat.rs index 9b1f1a41..2d454f07 100644 --- a/kernel-rs/src/fs/stat.rs +++ b/kernel-rs/src/fs/stat.rs @@ -1,4 +1,6 @@ -#[derive(Copy, Clone)] +use zerocopy::AsBytes; + +#[derive(Copy, Clone, AsBytes)] #[repr(C)] pub struct Stat { /// File system's disk device @@ -13,6 +15,9 @@ pub struct Stat { /// Number of links to file pub nlink: i16, + /// Padding for safetly serializing the struct + pub _padding: u32, + /// Size of file in bytes pub size: usize, } diff --git a/kernel-rs/src/kernel.rs b/kernel-rs/src/kernel.rs index fa35d407..b902fb54 100644 --- a/kernel-rs/src/kernel.rs +++ b/kernel-rs/src/kernel.rs @@ -30,9 +30,8 @@ use crate::{ static mut KERNEL: KernelBuilder = KernelBuilder::new(); /// After intialized, the kernel is safe to immutably access. -// TODO(https://github.com/kaist-cp/rv6/issues/515): make it unsafe #[inline] -pub fn kernel_builder<'s>() -> &'s KernelBuilder { +pub unsafe fn kernel_builder<'s>() -> &'s KernelBuilder { unsafe { &KERNEL } } @@ -99,9 +98,7 @@ pub struct KernelBuilder { pub itable: Itable, - // TODO(https://github.com/kaist-cp/rv6/issues/516) - // Make this private and always use `KernelRef::fs` instead. - pub file_system: FileSystem, + file_system: FileSystem, } #[repr(transparent)] @@ -298,7 +295,8 @@ impl KernelBuilder { #[macro_export] macro_rules! print { ($($arg:tt)*) => { - $crate::kernel::kernel_builder().printer_write_fmt(format_args!($($arg)*)).unwrap(); + // TODO(https://github.com/kaist-cp/rv6/issues/267): remove kernel_builder() + unsafe { $crate::kernel::kernel_builder() }.printer_write_fmt(format_args!($($arg)*)).unwrap(); }; } @@ -309,12 +307,12 @@ macro_rules! println { ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); } -/// Handles panic. +/// Handles panic by freezing other CPUs. #[cfg(not(test))] #[panic_handler] fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { - // Freeze other CPUs. - kernel_builder().panic(); + // SAFETY: it is called only after the kernel is initialized. + unsafe { kernel_builder() }.panic(); println!("{}", info); spin_loop() diff --git a/kernel-rs/src/param.rs b/kernel-rs/src/param.rs index 3dfffe66..7b81fbe6 100644 --- a/kernel-rs/src/param.rs +++ b/kernel-rs/src/param.rs @@ -35,11 +35,6 @@ pub const LOGSIZE: usize = MAXOPBLOCKS * 3; /// Size of disk block cache. pub const NBUF: usize = MAXOPBLOCKS * 3; -// TODO(https://github.com/kaist-cp/rv6/issues/120): `FSSIZE` seems no longer used. -#[allow(dead_code)] -/// Size of file system in blocks. -pub const FSSIZE: usize = 2000; - /// Maximum file path name. pub const MAXPATH: usize = 128; diff --git a/kernel-rs/src/proc/mod.rs b/kernel-rs/src/proc/mod.rs index 6b85fef8..5c255ef7 100644 --- a/kernel-rs/src/proc/mod.rs +++ b/kernel-rs/src/proc/mod.rs @@ -458,7 +458,7 @@ impl<'id> ProcGuard<'id, '_> { let data = unsafe { self.deref_mut_data() }; let trap_frame = mem::replace(&mut data.trap_frame, ptr::null_mut()); // TODO(https://github.com/kaist-cp/rv6/issues/267): remove kernel_builder() - let allocator = &kernel_builder().kmem; + let allocator = &unsafe { kernel_builder() }.kmem; // SAFETY: trap_frame uniquely refers to a valid page. allocator.free(unsafe { Page::from_usize(trap_frame as _) }); // SAFETY: diff --git a/kernel-rs/src/proc/procs.rs b/kernel-rs/src/proc/procs.rs index 06575fa3..c0c636a4 100644 --- a/kernel-rs/src/proc/procs.rs +++ b/kernel-rs/src/proc/procs.rs @@ -175,7 +175,7 @@ impl Procs { let name = b"initcode\x00"; (&mut data.name[..name.len()]).copy_from_slice(name); // TODO(https://github.com/kaist-cp/rv6/issues/267): remove kernel_builder() - let _ = data.cwd.write(kernel_builder().itable.root()); + let _ = data.cwd.write(unsafe { kernel_builder() }.itable.root()); // It's safe because cwd now has been initialized. guard.deref_mut_info().state = Procstate::RUNNABLE; @@ -239,7 +239,7 @@ impl<'id, 's> ProcsRef<'id, 's> { } // TODO(https://github.com/kaist-cp/rv6/issues/267): remove kernel_builder() - let allocator = &kernel_builder().kmem; + let allocator = &unsafe { kernel_builder() }.kmem; allocator.free(trap_frame); memory.free(allocator); Err(()) @@ -425,7 +425,7 @@ impl<'id, 's> ProcsRef<'id, 's> { // by assigning None to self.cwd. Deallocation of an inode may cause // disk write operations, so we must begin a transaction here. let kernel = ctx.kernel(); - let tx = kernel.file_system.begin_transaction(); + let tx = kernel.fs().begin_transaction(); // SAFETY: CurrentProc's cwd has been initialized. // It's ok to drop cwd as proc will not be used any longer. unsafe { ctx.proc_mut().deref_mut_data().cwd.assume_init_drop() }; @@ -503,7 +503,7 @@ unsafe fn forkret() -> ! { // File system initialization must be run in the context of a // regular process (e.g., because it calls sleep), and thus cannot // be run from main(). - ctx.kernel().file_system.init(ROOTDEV, &ctx); + ctx.kernel().fs().init(ROOTDEV, &ctx); unsafe { ctx.user_trap_ret() } }; diff --git a/kernel-rs/src/trap.rs b/kernel-rs/src/trap.rs index f166a702..89f0166e 100644 --- a/kernel-rs/src/trap.rs +++ b/kernel-rs/src/trap.rs @@ -238,7 +238,7 @@ impl KernelRef<'_, '_> { // SAFETY: it's unsafe only when ctrl+p is pressed. unsafe { self.console.intr(self) }; } else if irq as usize == VIRTIO0_IRQ { - self.file_system.log.disk.lock().intr(self); + self.fs().log.disk.lock().intr(self); } else if irq != 0 { // Use `panic!` instead of `println` to prevent stack overflow. // https://github.com/kaist-cp/rv6/issues/311 diff --git a/kernel-rs/src/uart.rs b/kernel-rs/src/uart.rs index 97facaa2..125cb6df 100644 --- a/kernel-rs/src/uart.rs +++ b/kernel-rs/src/uart.rs @@ -1,4 +1,8 @@ //! Low-level driver routines for 16550a UART. + +// Dead code is allowed in this file because not all components are used in the kernel. +#![allow(dead_code)] + use core::ptr; use self::UartCtrlRegs::{FCR, IER, ISR, LCR, LSR, RBR, THR}; @@ -10,7 +14,6 @@ enum UartRegBits { FCRFifoClear, LCREightBits, LCRBaudLatch, - #[allow(dead_code)] LSRRxRead, LSRTxIdle, } @@ -48,7 +51,6 @@ enum UartCtrlRegs { /// FIFO Control Register. FCR, /// Interrupt Status Register. - #[allow(dead_code)] ISR, /// Line Control Register. LCR, diff --git a/kernel-rs/src/vm.rs b/kernel-rs/src/vm.rs index c2dcaf9f..ab097de3 100644 --- a/kernel-rs/src/vm.rs +++ b/kernel-rs/src/vm.rs @@ -1,6 +1,7 @@ use core::{cmp, marker::PhantomData, mem, slice}; use bitflags::bitflags; +use zerocopy::{AsBytes, FromBytes}; use crate::{ arch::addr::{ @@ -540,13 +541,8 @@ impl UserMemory { /// Copy from kernel to user. /// Copy from src to virtual address dstva in a given page table. /// Return Ok(()) on success, Err(()) on error. - pub fn copy_out(&mut self, dstva: UVAddr, src: &T) -> Result<(), ()> { - self.copy_out_bytes( - dstva, - // SAFETY: src is a valid reference to T and - // u8 does not have any internal structure. - unsafe { core::slice::from_raw_parts_mut(src as *const _ as _, mem::size_of::()) }, - ) + pub fn copy_out(&mut self, dstva: UVAddr, src: &T) -> Result<(), ()> { + self.copy_out_bytes(dstva, src.as_bytes()) } /// Copy from user to kernel. @@ -572,15 +568,12 @@ impl UserMemory { /// Copy from user to kernel. /// Copy to dst from virtual address srcva in a given page table. /// Return Ok(()) on success, Err(()) on error. - /// - /// # Safety - /// - /// `T` can be safely `transmute`d to `[u8; size_of::()]`. - pub unsafe fn copy_in(&mut self, dst: &mut T, srcva: UVAddr) -> Result<(), ()> { - self.copy_in_bytes( - unsafe { core::slice::from_raw_parts_mut(dst as *mut _ as _, mem::size_of::()) }, - srcva, - ) + pub unsafe fn copy_in( + &mut self, + dst: &mut T, + srcva: UVAddr, + ) -> Result<(), ()> { + self.copy_in_bytes(dst.as_bytes_mut(), srcva) } /// Copy a null-terminated string from user to kernel.