diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 274b88f..1f53782 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -67,10 +67,10 @@ | 0x40 (64) | write | (unsigned int fd, const char *buf, size_t count) | __arm64_sys_write | true | | 0x41 (65) | readv | (unsigned long fd, const struct iovec *vec, unsigned long vlen) | __arm64_sys_readv | true | | 0x42 (66) | writev | (unsigned long fd, const struct iovec *vec, unsigned long vlen) | __arm64_sys_writev | true | -| 0x43 (67) | pread64 | (unsigned int fd, char *buf, size_t count, loff_t pos) | __arm64_sys_pread64 | false | -| 0x44 (68) | pwrite64 | (unsigned int fd, const char *buf, size_t count, loff_t pos) | __arm64_sys_pwrite64 | false | -| 0x45 (69) | preadv | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h) | __arm64_sys_preadv | false | -| 0x46 (70) | pwritev | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h) | __arm64_sys_pwritev | false | +| 0x43 (67) | pread64 | (unsigned int fd, char *buf, size_t count, loff_t pos) | __arm64_sys_pread64 | true | +| 0x44 (68) | pwrite64 | (unsigned int fd, const char *buf, size_t count, loff_t pos) | __arm64_sys_pwrite64 | true | +| 0x45 (69) | preadv | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h) | __arm64_sys_preadv | true | +| 0x46 (70) | pwritev | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h) | __arm64_sys_pwritev | true | | 0x47 (71) | sendfile64 | (int out_fd, int in_fd, loff_t *offset, size_t count) | __arm64_sys_sendfile64 | true | | 0x48 (72) | pselect6 | (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct __kernel_timespec *tsp, void *sig) | __arm64_sys_pselect6 | true | | 0x49 (73) | ppoll | (struct pollfd *ufds, unsigned int nfds, struct __kernel_timespec *tsp, const sigset_t *sigmask, size_t sigsetsize) | __arm64_sys_ppoll | true | @@ -270,8 +270,8 @@ | 0x11b (283) | membarrier | (int cmd, unsigned int flags, int cpu_id) | __arm64_sys_membarrier | false | | 0x11c (284) | mlock2 | (unsigned long start, size_t len, int flags) | __arm64_sys_mlock2 | false | | 0x11d (285) | copy_file_range | (int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) | __arm64_sys_copy_file_range | false | -| 0x11e (286) | preadv2 | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags) | __arm64_sys_preadv2 | false | -| 0x11f (287) | pwritev2 | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags) | __arm64_sys_pwritev2 | false | +| 0x11e (286) | preadv2 | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags) | __arm64_sys_preadv2 | true | +| 0x11f (287) | pwritev2 | (unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags) | __arm64_sys_pwritev2 | true | | 0x120 (288) | pkey_mprotect | (unsigned long start, size_t len, unsigned long prot, int pkey) | __arm64_sys_pkey_mprotect | false | | 0x121 (289) | pkey_alloc | (unsigned long flags, unsigned long init_val) | __arm64_sys_pkey_alloc | false | | 0x122 (290) | pkey_free | (int pkey) | __arm64_sys_pkey_free | false | diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 92337c0..8a07881 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -24,8 +24,8 @@ use crate::{ chown::sys_fchown, close::sys_close, ioctl::sys_ioctl, - iov::{sys_readv, sys_writev}, - rw::{sys_read, sys_write}, + iov::{sys_preadv, sys_preadv2, sys_pwritev, sys_pwritev2, sys_readv, sys_writev}, + rw::{sys_pread64, sys_pwrite64, sys_read, sys_write}, seek::sys_lseek, splice::sys_sendfile, stat::sys_fstat, @@ -172,6 +172,42 @@ pub async fn handle_syscall() { 0x40 => sys_write(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x41 => sys_readv(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x42 => sys_writev(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, + 0x43 => { + sys_pread64( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + ) + .await + } + 0x44 => { + sys_pwrite64( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + ) + .await + } + 0x45 => { + sys_preadv( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + ) + .await + } + 0x46 => { + sys_pwritev( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + ) + .await + } 0x47 => { sys_sendfile( arg1.into(), @@ -364,6 +400,26 @@ pub async fn handle_syscall() { .await } 0x116 => sys_getrandom(TUA::from_value(arg1 as _), arg2 as _, arg3 as _).await, + 0x11e => { + sys_preadv2( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + arg5 as _, + ) + .await + } + 0x11f => { + sys_pwritev2( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + arg5 as _, + ) + .await + } 0x125 => Err(KernelError::NotSupported), 0x1b7 => { sys_faccessat2( diff --git a/src/console/tty.rs b/src/console/tty.rs index 4f3858d..5ccaa12 100644 --- a/src/console/tty.rs +++ b/src/console/tty.rs @@ -84,6 +84,10 @@ impl Tty { #[async_trait] impl FileOps for Tty { async fn read(&mut self, _ctx: &mut FileCtx, usr_buf: UA, count: usize) -> Result { + self.readat(usr_buf, count, 0).await + } + + async fn readat(&mut self, usr_buf: UA, count: usize, _offset: u64) -> Result { let (cooked_pipe, eof_fut) = { let cooker = self.input_cooker.lock_save_irq(); @@ -129,7 +133,11 @@ impl FileOps for Tty { }) } - async fn write(&mut self, _ctx: &mut FileCtx, mut ptr: UA, count: usize) -> Result { + async fn write(&mut self, _ctx: &mut FileCtx, ptr: UA, count: usize) -> Result { + self.writeat(ptr, count, 0).await + } + + async fn writeat(&mut self, mut ptr: UA, count: usize, _offset: u64) -> Result { const CHUNK_SZ: usize = 128; let mut remaining = count; diff --git a/src/drivers/null.rs b/src/drivers/null.rs index f593540..da6785b 100644 --- a/src/drivers/null.rs +++ b/src/drivers/null.rs @@ -3,7 +3,7 @@ use crate::{ CharDriver, DriverManager, OpenableDevice, ReservedMajors, fs::dev::devfs, init::PlatformBus, }, - fs::{fops::FileOps, open_file::FileCtx, open_file::OpenFile}, + fs::{fops::FileOps, open_file::OpenFile}, kernel_driver, }; use alloc::string::ToString; @@ -22,12 +22,12 @@ struct NullFileOps; #[async_trait] impl FileOps for NullFileOps { - async fn read(&mut self, _ctx: &mut FileCtx, _buf: UA, _count: usize) -> Result { + async fn readat(&mut self, _buf: UA, _count: usize, _offset: u64) -> Result { // EOF Ok(0) } - async fn write(&mut self, _ctx: &mut FileCtx, _buf: UA, count: usize) -> Result { + async fn writeat(&mut self, _buf: UA, count: usize, _offset: u64) -> Result { // Pretend we wrote everything successfully. Ok(count) } diff --git a/src/drivers/zero.rs b/src/drivers/zero.rs index a1d3e4e..db4bc66 100644 --- a/src/drivers/zero.rs +++ b/src/drivers/zero.rs @@ -25,7 +25,11 @@ struct ZeroFileOps; #[async_trait] impl FileOps for ZeroFileOps { - async fn read(&mut self, _ctx: &mut FileCtx, mut buf: UA, mut count: usize) -> Result { + async fn read(&mut self, _ctx: &mut FileCtx, buf: UA, count: usize) -> Result { + self.readat(buf, count, 0).await + } + + async fn readat(&mut self, mut buf: UA, mut count: usize, _offset: u64) -> Result { let requested = count; while count > 0 { @@ -39,7 +43,11 @@ impl FileOps for ZeroFileOps { Ok(requested) } - async fn write(&mut self, _ctx: &mut FileCtx, _buf: UA, count: usize) -> Result { + async fn write(&mut self, _ctx: &mut FileCtx, buf: UA, count: usize) -> Result { + self.writeat(buf, count, 0).await + } + + async fn writeat(&mut self, _buf: UA, count: usize, _offset: u64) -> Result { Ok(count) } diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 7970092..4713dd3 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -62,10 +62,18 @@ impl FileOps for DirFile { Err(FsError::IsADirectory.into()) } + async fn readat(&mut self, _buf: UA, _count: usize, _offset: u64) -> Result { + Err(FsError::IsADirectory.into()) + } + async fn write(&mut self, _ctx: &mut FileCtx, _buf: UA, _count: usize) -> Result { Err(FsError::IsADirectory.into()) } + async fn writeat(&mut self, _buf: UA, _count: usize, _offset: u64) -> Result { + Err(FsError::IsADirectory.into()) + } + async fn readdir<'a>(&'a mut self, ctx: &'a mut FileCtx) -> Result> { if self.inode.getattr().await?.file_type != FileType::Directory { return Err(FsError::NotADirectory.into()); diff --git a/src/fs/fops.rs b/src/fs/fops.rs index 0b340aa..6388cd0 100644 --- a/src/fs/fops.rs +++ b/src/fs/fops.rs @@ -42,16 +42,32 @@ macro_rules! process_iovec { pub trait FileOps: Send + Sync { /// Reads data from the current file position into `buf`. /// The file's cursor is advanced by the number of bytes read. - async fn read(&mut self, ctx: &mut FileCtx, buf: UA, count: usize) -> Result; + async fn read(&mut self, ctx: &mut FileCtx, buf: UA, count: usize) -> Result { + let total_bytes_read = self.readat(buf, count, ctx.pos).await?; + ctx.pos += total_bytes_read as u64; + Ok(total_bytes_read) + } + + async fn readat(&mut self, buf: UA, count: usize, offset: u64) -> Result; /// Writes data from `buf` to the current file position. /// The file's cursor is advanced by the number of bytes written. - async fn write(&mut self, ctx: &mut FileCtx, buf: UA, count: usize) -> Result; + async fn write(&mut self, ctx: &mut FileCtx, buf: UA, count: usize) -> Result { + let total_bytes_written = self.writeat(buf, count, ctx.pos).await?; + ctx.pos += total_bytes_written as u64; + Ok(total_bytes_written) + } + + async fn writeat(&mut self, buf: UA, count: usize, offset: u64) -> Result; async fn readv(&mut self, ctx: &mut FileCtx, iovecs: &[IoVec]) -> Result { process_iovec!(iovecs, |addr, count| self.read(ctx, addr, count)).await } + async fn readvat(&mut self, iovecs: &[IoVec], offset: u64) -> Result { + process_iovec!(iovecs, |addr, count| self.readat(addr, count, offset)).await + } + async fn readdir<'a>(&'a mut self, _ctx: &'a mut FileCtx) -> Result> { Err(FsError::NotADirectory.into()) } @@ -60,6 +76,10 @@ pub trait FileOps: Send + Sync { process_iovec!(iovecs, |addr, count| self.write(ctx, addr, count)).await } + async fn writevat(&mut self, iovecs: &[IoVec], offset: u64) -> Result { + process_iovec!(iovecs, |addr, count| self.writeat(addr, count, offset)).await + } + /// Puts the current task to sleep until a call to `read()` would no longer /// block. fn poll_read_ready(&self) -> Pin> + 'static + Send>> { diff --git a/src/fs/pipe.rs b/src/fs/pipe.rs index 406847a..a0ed561 100644 --- a/src/fs/pipe.rs +++ b/src/fs/pipe.rs @@ -61,6 +61,10 @@ impl PipeReader { #[async_trait] impl FileOps for PipeReader { async fn read(&mut self, _ctx: &mut FileCtx, u_buf: UA, count: usize) -> Result { + self.readat(u_buf, count, 0).await + } + + async fn readat(&mut self, u_buf: UA, count: usize, _offset: u64) -> Result { if count == 0 { return Ok(0); } @@ -73,6 +77,10 @@ impl FileOps for PipeReader { Err(KernelError::BadFd) } + async fn writeat(&mut self, _buf: UA, _count: usize, _offset: u64) -> Result { + Err(KernelError::BadFd) + } + async fn seek(&mut self, _ctx: &mut FileCtx, _pos: SeekFrom) -> Result { Err(KernelError::SeekPipe) } @@ -135,7 +143,15 @@ impl FileOps for PipeWriter { Err(KernelError::BadFd) } + async fn readat(&mut self, _buf: UA, _count: usize, _offset: u64) -> Result { + Err(KernelError::BadFd) + } + async fn write(&mut self, _ctx: &mut FileCtx, u_buf: UA, count: usize) -> Result { + self.writeat(u_buf, count, 0).await + } + + async fn writeat(&mut self, u_buf: UA, count: usize, _offset: u64) -> Result { if count == 0 { return Ok(0); } diff --git a/src/fs/reg.rs b/src/fs/reg.rs index 2a93f46..fba4c74 100644 --- a/src/fs/reg.rs +++ b/src/fs/reg.rs @@ -31,11 +31,11 @@ impl RegFile { impl FileOps for RegFile { /// Reads data from the current file position into `buf`. The file's cursor /// is advanced by the number of bytes read. - async fn read( + async fn readat( &mut self, - ctx: &mut FileCtx, mut user_buf: UA, mut count: usize, + mut offset: u64, ) -> Result { let mut pg = ClaimedPage::alloc_zeroed()?; let kbuf = pg.as_slice_mut(); @@ -45,7 +45,7 @@ impl FileOps for RegFile { let chunk_sz = min(PAGE_SIZE, count); copy_from_user_slice(user_buf, &mut kbuf[..chunk_sz]).await?; - let bytes_read = self.inode.read_at(ctx.pos, &mut kbuf[..chunk_sz]).await?; + let bytes_read = self.inode.read_at(offset, &mut kbuf[..chunk_sz]).await?; if bytes_read == 0 { break; @@ -53,7 +53,7 @@ impl FileOps for RegFile { copy_to_user_slice(&kbuf[..bytes_read], user_buf).await?; - ctx.pos += bytes_read as u64; + offset += bytes_read as u64; total_bytes_read += bytes_read; user_buf = user_buf.add_bytes(bytes_read); count -= bytes_read; @@ -64,7 +64,7 @@ impl FileOps for RegFile { /// Writes data from `buf` to the current file position. /// The file's cursor is advanced by the number of bytes written. - async fn write(&mut self, ctx: &mut FileCtx, mut buf: UA, mut count: usize) -> Result { + async fn writeat(&mut self, mut buf: UA, mut count: usize, mut offset: u64) -> Result { let mut pg = ClaimedPage::alloc_zeroed()?; let kbuf = pg.as_slice_mut(); let mut total_bytes_written = 0; @@ -74,7 +74,7 @@ impl FileOps for RegFile { copy_from_user_slice(buf, &mut kbuf[..chunk_sz]).await?; - let bytes_written = self.inode.write_at(ctx.pos, &kbuf[..chunk_sz]).await?; + let bytes_written = self.inode.write_at(offset, &kbuf[..chunk_sz]).await?; // If we wrote 0 bytes, the disk might be full or the file cannot be // extended. @@ -82,7 +82,7 @@ impl FileOps for RegFile { break; } - ctx.pos += bytes_written as u64; + offset += bytes_written as u64; total_bytes_written += bytes_written; count -= bytes_written; buf = buf.add_bytes(bytes_written); diff --git a/src/fs/syscalls/iov.rs b/src/fs/syscalls/iov.rs index ee02539..0a334c3 100644 --- a/src/fs/syscalls/iov.rs +++ b/src/fs/syscalls/iov.rs @@ -45,3 +45,51 @@ pub async fn sys_readv(fd: Fd, iov_ptr: TUA, no_iov: usize) -> Result, no_iov: usize, offset: u64) -> Result { + sys_pwritev2(fd, iov_ptr, no_iov, offset, 0).await +} + +pub async fn sys_preadv(fd: Fd, iov_ptr: TUA, no_iov: usize, offset: u64) -> Result { + sys_preadv2(fd, iov_ptr, no_iov, offset, 0).await +} + +pub async fn sys_pwritev2( + fd: Fd, + iov_ptr: TUA, + no_iov: usize, + offset: u64, + _flags: u32, // TODO: implement these flags +) -> Result { + let file = current_task() + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + + let iovs = copy_obj_array_from_user(iov_ptr, no_iov).await?; + + let (ops, _state) = &mut *file.lock().await; + + ops.writevat(&iovs, offset).await +} + +pub async fn sys_preadv2( + fd: Fd, + iov_ptr: TUA, + no_iov: usize, + offset: u64, + _flags: u32, +) -> Result { + let file = current_task() + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + + let iovs = copy_obj_array_from_user(iov_ptr, no_iov).await?; + + let (ops, _state) = &mut *file.lock().await; + + ops.readvat(&iovs, offset).await +} diff --git a/src/fs/syscalls/rw.rs b/src/fs/syscalls/rw.rs index 0a1141f..960bbe6 100644 --- a/src/fs/syscalls/rw.rs +++ b/src/fs/syscalls/rw.rs @@ -27,3 +27,27 @@ pub async fn sys_read(fd: Fd, user_buf: UA, count: usize) -> Result { ops.read(ctx, user_buf, count).await } + +pub async fn sys_pwrite64(fd: Fd, user_buf: UA, count: usize, offset: u64) -> Result { + let file = current_task() + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + + let (ops, _ctx) = &mut *file.lock().await; + + ops.writeat(user_buf, count, offset).await +} + +pub async fn sys_pread64(fd: Fd, user_buf: UA, count: usize, offset: u64) -> Result { + let file = current_task() + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + + let (ops, _ctx) = &mut *file.lock().await; + + ops.readat(user_buf, count, offset).await +} diff --git a/usertest/src/main.rs b/usertest/src/main.rs index ce127e3..745922b 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -482,13 +482,17 @@ fn test_ftruncate() { let mut buffer = [1u8; 5]; unsafe { let fd = libc::open(c_file.as_ptr(), libc::O_RDWR | libc::O_CREAT, 0o777); - let ret = libc::write(fd, data.as_ptr() as *const libc::c_void, data.len()); + let ret = libc::pwrite64(fd, data.as_ptr() as *const libc::c_void, data.len(), 0); if ret < 0 || ret as usize != data.len() { panic!("write failed"); } libc::ftruncate(fd, 5); - libc::lseek(fd, 0, libc::SEEK_SET); - let ret = libc::read(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()); + let ret = libc::pread64( + fd, + buffer.as_mut_ptr() as *mut libc::c_void, + buffer.len(), + 0, + ); if ret < 0 || ret as usize != 5 { panic!("read failed"); }