rewrite more syscalls

This commit is contained in:
Garen Tyler 2023-10-31 17:29:50 -06:00
parent f0c0f26beb
commit 6e5520f481
Signed by: garentyler
GPG Key ID: D7A048C454CB7054
6 changed files with 267 additions and 204 deletions

View File

@ -54,23 +54,28 @@ impl File {
#[repr(C)]
pub struct Inode {
/// Device number.
device: u32,
pub device: u32,
/// Inode number.
inum: u32,
pub inum: u32,
/// Reference count.
references: i32,
pub references: i32,
lock: Sleeplock,
pub lock: Sleeplock,
/// Inode has been read from disk?
valid: i32,
pub valid: i32,
// Copy of DiskInode
kind: i16,
major: i16,
minor: i16,
num_links: i16,
size: u32,
addresses: [u32; crate::fs::NDIRECT + 1],
pub kind: i16,
pub major: i16,
pub minor: i16,
pub num_links: i16,
pub size: u32,
pub addresses: [u32; crate::fs::NDIRECT + 1],
}
impl Inode {
pub fn lock(&mut self) -> InodeLockGuard<'_> {
InodeLockGuard::new(self)
}
}
pub struct InodeLockGuard<'i> {
@ -236,7 +241,10 @@ pub unsafe extern "C" fn fileread(file: *mut File, addr: u64, num_bytes: i32) ->
}
match (*file).kind {
FileType::Pipe => (*(*file).pipe).read(addr, num_bytes as usize).map(|n| n as i32).unwrap_or(-1i32),
FileType::Pipe => (*(*file).pipe)
.read(addr, num_bytes as usize)
.map(|n| n as i32)
.unwrap_or(-1i32),
FileType::Device => {
if (*file).major < 0 || (*file).major >= crate::NDEV as i16 {
return -1;
@ -269,7 +277,10 @@ pub unsafe extern "C" fn filewrite(file: *mut File, addr: u64, num_bytes: i32) -
}
match (*file).kind {
FileType::Pipe => (*(*file).pipe).write(addr, num_bytes as usize).map(|n| n as i32).unwrap_or(-1i32),
FileType::Pipe => (*(*file).pipe)
.write(addr, num_bytes as usize)
.map(|n| n as i32)
.unwrap_or(-1i32),
FileType::Device => {
if (*file).major < 0 || (*file).major >= crate::NDEV as i16 {
return -1;

View File

@ -100,5 +100,6 @@ extern "C" {
pub fn stati(ip: *mut Inode, st: *mut stat::Stat);
pub fn readi(ip: *mut Inode, user_dst: i32, dst: u64, off: u32, n: u32) -> i32;
pub fn writei(ip: *mut Inode, user_src: i32, src: u64, off: u32, n: u32) -> i32;
pub fn namei(path: *mut u8) -> *mut Inode;
// pub fn namecmp()
}

View File

@ -1,9 +1,6 @@
#[repr(C)]
pub enum StatType {
Directory = 1,
File,
Device,
}
pub const KIND_DIR: i16 = 1;
pub const KIND_FILE: i16 = 2;
pub const KIND_DEVICE: i16 = 3;
#[repr(C)]
#[derive(Default)]

View File

@ -2,6 +2,7 @@
use crate::{
arch::riscv::{intr_get, r_tp, Pagetable, PTE_W},
fs::file::{File, Inode},
mem::kalloc::kfree,
sync::spinlock::{Spinlock, SpinlockGuard},
};
@ -214,9 +215,9 @@ pub struct Proc {
/// swtch() here to run process
pub context: Context,
/// Open files
pub ofile: *mut u8, // TODO: Change u8 ptr to File ptr.
pub ofile: [*mut File; crate::NOFILE],
/// Current directory
pub cwd: *mut u8, // TODO: Change u8 ptr to inode ptr.
pub cwd: *mut Inode,
/// Process name (debugging)
pub name: [c_char; 16],
}

View File

@ -1,30 +1,33 @@
use crate::{
arch::riscv::memlayout::QEMU_POWER,
fs::{
self,
file::{self, File, Inode},
log::{self, LogOperation},
stat::KIND_DIR,
},
mem::virtual_memory::{copyin, copyinstr},
println,
proc::{self, myproc},
string::strlen,
trap::CLOCK_TICKS,
NOFILE,
};
use core::{
mem::size_of,
ptr::{addr_of, addr_of_mut},
ptr::{addr_of, addr_of_mut, null_mut},
};
extern "C" {
fn sys_pipe() -> u64;
fn sys_read() -> u64;
fn sys_exec() -> u64;
fn sys_fstat() -> u64;
fn sys_chdir() -> u64;
fn sys_dup() -> u64;
fn sys_open() -> u64;
fn sys_write() -> u64;
fn sys_mknod() -> u64;
fn sys_unlink() -> u64;
fn sys_link() -> u64;
fn sys_mkdir() -> u64;
fn sys_close() -> u64;
}
pub enum Syscall {
@ -66,16 +69,76 @@ impl Syscall {
proc::wait(p) as u64
}
Syscall::Pipe => sys_pipe(),
Syscall::Read => sys_read(),
Syscall::Read => {
let mut file: *mut File = null_mut();
let mut num_bytes: i32 = 0;
let mut ptr: u64 = 0;
if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 {
argaddr(1, addr_of_mut!(ptr));
argint(2, addr_of_mut!(num_bytes));
file::fileread(file, ptr, num_bytes) as i64 as u64
} else {
-1i64 as u64
}
}
Syscall::Kill => {
let mut pid = 0i32;
argint(0, addr_of_mut!(pid));
proc::kill(pid) as u64
}
Syscall::Exec => sys_exec(),
Syscall::Fstat => sys_fstat(),
Syscall::Chdir => sys_chdir(),
Syscall::Dup => sys_dup(),
Syscall::Fstat => {
let mut file: *mut File = null_mut();
// User pointer to struct stat.
let mut stat: u64 = 0;
if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 {
argaddr(1, addr_of_mut!(stat));
file::filestat(file, stat) as i64 as u64
} else {
-1i64 as u64
}
}
Syscall::Chdir => {
let mut path = [0u8; crate::MAXPATH];
let mut inode: *mut Inode = null_mut();
let mut p = myproc();
let _operation = LogOperation::new();
if argstr(0, addr_of_mut!(path).cast(), path.len() as i32) < 0 {
return -1i64 as u64;
}
inode = fs::namei(addr_of_mut!(path).cast());
if inode.is_null() {
return -1i64 as u64;
}
fs::ilock(inode);
if (*inode).kind != KIND_DIR {
fs::iunlock(inode);
fs::iput(inode);
return -1i64 as u64;
}
fs::iunlock(inode);
fs::iput((*p).cwd);
(*p).cwd = inode;
0
}
Syscall::Dup => {
let mut file: *mut File = null_mut();
if argfd(0, null_mut(), addr_of_mut!(file)) < 0 {
return -1i64 as u64;
}
let Ok(file_descriptor) = fdalloc(file) else {
return -1i64 as u64;
};
file::filedup(file);
file_descriptor as u64
}
Syscall::Getpid => (*myproc()).pid as u64,
Syscall::Sbrk => {
let mut n = 0i32;
@ -106,12 +169,36 @@ impl Syscall {
// Returns how many clock tick interrupts have occured since start.
Syscall::Uptime => *CLOCK_TICKS.lock_spinning() as u64,
Syscall::Open => sys_open(),
Syscall::Write => sys_write(),
Syscall::Write => {
let mut file: *mut File = null_mut();
let mut num_bytes: i32 = 0;
let mut ptr: u64 = 0;
if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 {
argaddr(1, addr_of_mut!(ptr));
argint(2, addr_of_mut!(num_bytes));
file::filewrite(file, ptr, num_bytes) as i64 as u64
} else {
-1i64 as u64
}
}
Syscall::Mknod => sys_mknod(),
Syscall::Unlink => sys_unlink(),
Syscall::Link => sys_link(),
Syscall::Mkdir => sys_mkdir(),
Syscall::Close => sys_close(),
Syscall::Close => {
let mut file_descriptor: i32 = 0;
let mut file: *mut File = null_mut();
if argfd(0, addr_of_mut!(file_descriptor), addr_of_mut!(file)) >= 0 {
(*myproc()).ofile[file_descriptor as usize] = null_mut();
file::fileclose(file);
0
} else {
-1i64 as u64
}
}
Syscall::Shutdown => {
let qemu_power = QEMU_POWER as usize as *mut u32;
qemu_power.write_volatile(0x5555u32);
@ -214,10 +301,22 @@ pub unsafe extern "C" fn fetchstr(addr: u64, buf: *mut u8, max: i32) -> i32 {
}
}
#[no_mangle]
pub unsafe extern "C" fn argraw(n: i32) -> u64 {
/// Allocate a file descriptor for the given file.
/// Takes over file reference from caller on success.
unsafe fn fdalloc(file: *mut File) -> Result<usize, ()> {
let p = myproc();
match n {
for file_descriptor in 0..crate::NOFILE {
if (*p).ofile[file_descriptor].is_null() {
(*p).ofile[file_descriptor] = file;
return Ok(file_descriptor);
}
}
Err(())
}
unsafe fn argraw(argument_index: usize) -> u64 {
let p = myproc();
match argument_index {
0 => (*(*p).trapframe).a0,
1 => (*(*p).trapframe).a1,
2 => (*(*p).trapframe).a2,
@ -231,7 +330,7 @@ pub unsafe extern "C" fn argraw(n: i32) -> u64 {
/// Fetch the n-th 32-bit syscall argument.
#[no_mangle]
pub unsafe extern "C" fn argint(n: i32, ip: *mut i32) {
*ip = argraw(n) as i32;
*ip = argraw(n as usize) as i32;
}
/// Retrieve an argument as a pointer.
@ -240,7 +339,34 @@ pub unsafe extern "C" fn argint(n: i32, ip: *mut i32) {
/// copyin/copyout will do that.
#[no_mangle]
pub unsafe extern "C" fn argaddr(n: i32, ip: *mut u64) {
*ip = argraw(n);
*ip = argraw(n as usize);
}
/// Fetch the n-th word-sized syscall argument as a file descriptor
/// and return both the descriptor and the corresponding struct file.
#[no_mangle]
pub unsafe extern "C" fn argfd(
n: i32,
file_descriptor_out: *mut i32,
file_out: *mut *mut File,
) -> i32 {
let file_descriptor = argraw(n as usize) as usize;
if file_descriptor >= NOFILE {
return -1;
}
let file: *mut File = (*myproc()).ofile[file_descriptor];
if file.is_null() {
return -1;
}
if !file_descriptor_out.is_null() {
*file_descriptor_out = file_descriptor as i32;
}
if !file_out.is_null() {
*file_out = file;
}
0
}
/// Fetch the n-th word-sized syscall argument as a null-terminated string.

View File

@ -18,21 +18,7 @@
// Fetch the nth word-sized system call argument as a file descriptor
// and return both the descriptor and the corresponding struct file.
static int
argfd(int n, int *pfd, struct file **pf)
{
int fd;
struct file *f;
argint(n, &fd);
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
return -1;
if(pfd)
*pfd = fd;
if(pf)
*pf = f;
return 0;
}
int argfd(int n, int *pfd, struct file **pf);
// Allocate a file descriptor for the given file.
// Takes over file reference from caller on success.
@ -42,8 +28,10 @@ fdalloc(struct file *f)
int fd;
struct proc *p = myproc();
for(fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd] == 0){
for (fd = 0; fd < NOFILE; fd++)
{
if (p->ofile[fd] == 0)
{
p->ofile[fd] = f;
return fd;
}
@ -51,74 +39,6 @@ fdalloc(struct file *f)
return -1;
}
uint64
sys_dup(void)
{
struct file *f;
int fd;
if(argfd(0, 0, &f) < 0)
return -1;
if((fd=fdalloc(f)) < 0)
return -1;
filedup(f);
return fd;
}
uint64
sys_read(void)
{
struct file *f;
int n;
uint64 p;
argaddr(1, &p);
argint(2, &n);
if(argfd(0, 0, &f) < 0)
return -1;
return fileread(f, p, n);
}
uint64
sys_write(void)
{
struct file *f;
int n;
uint64 p;
argaddr(1, &p);
argint(2, &n);
if(argfd(0, 0, &f) < 0)
return -1;
return filewrite(f, p, n);
}
uint64
sys_close(void)
{
int fd;
struct file *f;
if(argfd(0, &fd, &f) < 0)
return -1;
myproc()->ofile[fd] = 0;
fileclose(f);
return 0;
}
uint64
sys_fstat(void)
{
struct file *f;
uint64 st; // user pointer to struct stat
argaddr(1, &st);
if(argfd(0, 0, &f) < 0)
return -1;
return filestat(f, st);
}
// Create the path new as a link to the same inode as old.
uint64
sys_link(void)
@ -126,17 +46,19 @@ sys_link(void)
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
struct inode *dp, *ip;
if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
if (argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
return -1;
begin_op();
if((ip = namei(old)) == 0){
if ((ip = namei(old)) == 0)
{
end_op();
return -1;
}
ilock(ip);
if(ip->type == T_DIR){
if (ip->type == T_DIR)
{
iunlockput(ip);
end_op();
return -1;
@ -146,10 +68,11 @@ sys_link(void)
iupdate(ip);
iunlock(ip);
if((dp = nameiparent(new, name)) == 0)
if ((dp = nameiparent(new, name)) == 0)
goto bad;
ilock(dp);
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0)
{
iunlockput(dp);
goto bad;
}
@ -176,10 +99,11 @@ isdirempty(struct inode *dp)
int off;
struct dirent de;
for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
for (off = 2 * sizeof(de); off < dp->size; off += sizeof(de))
{
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("isdirempty: readi");
if(de.inum != 0)
if (de.inum != 0)
return 0;
}
return 1;
@ -193,11 +117,12 @@ sys_unlink(void)
char name[DIRSIZ], path[MAXPATH];
uint off;
if(argstr(0, path, MAXPATH) < 0)
if (argstr(0, path, MAXPATH) < 0)
return -1;
begin_op();
if((dp = nameiparent(path, name)) == 0){
if ((dp = nameiparent(path, name)) == 0)
{
end_op();
return -1;
}
@ -205,24 +130,26 @@ sys_unlink(void)
ilock(dp);
// Cannot unlink "." or "..".
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
if (namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
goto bad;
if((ip = dirlookup(dp, name, &off)) == 0)
if ((ip = dirlookup(dp, name, &off)) == 0)
goto bad;
ilock(ip);
if(ip->nlink < 1)
if (ip->nlink < 1)
panic("unlink: nlink < 1");
if(ip->type == T_DIR && !isdirempty(ip)){
if (ip->type == T_DIR && !isdirempty(ip))
{
iunlockput(ip);
goto bad;
}
memset(&de, 0, sizeof(de));
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("unlink: writei");
if(ip->type == T_DIR){
if (ip->type == T_DIR)
{
dp->nlink--;
iupdate(dp);
}
@ -242,27 +169,29 @@ bad:
return -1;
}
static struct inode*
static struct inode *
create(char *path, short type, short major, short minor)
{
struct inode *ip, *dp;
char name[DIRSIZ];
if((dp = nameiparent(path, name)) == 0)
if ((dp = nameiparent(path, name)) == 0)
return 0;
ilock(dp);
if((ip = dirlookup(dp, name, 0)) != 0){
if ((ip = dirlookup(dp, name, 0)) != 0)
{
iunlockput(dp);
ilock(ip);
if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
if (type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
return ip;
iunlockput(ip);
return 0;
}
if((ip = ialloc(dp->dev, type)) == 0){
if ((ip = ialloc(dp->dev, type)) == 0)
{
iunlockput(dp);
return 0;
}
@ -273,18 +202,20 @@ create(char *path, short type, short major, short minor)
ip->nlink = 1;
iupdate(ip);
if(type == T_DIR){ // Create . and .. entries.
if (type == T_DIR)
{ // Create . and .. entries.
// No ip->nlink++ for ".": avoid cyclic ref count.
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
goto fail;
}
if(dirlink(dp, name, ip->inum) < 0)
if (dirlink(dp, name, ip->inum) < 0)
goto fail;
if(type == T_DIR){
if (type == T_DIR)
{
// now that success is guaranteed:
dp->nlink++; // for ".."
dp->nlink++; // for ".."
iupdate(dp);
}
@ -292,7 +223,7 @@ create(char *path, short type, short major, short minor)
return ip;
fail:
fail:
// something went wrong. de-allocate ip.
ip->nlink = 0;
iupdate(ip);
@ -311,48 +242,59 @@ sys_open(void)
int n;
argint(1, &omode);
if((n = argstr(0, path, MAXPATH)) < 0)
if ((n = argstr(0, path, MAXPATH)) < 0)
return -1;
begin_op();
if(omode & O_CREATE){
if (omode & O_CREATE)
{
ip = create(path, T_FILE, 0, 0);
if(ip == 0){
if (ip == 0)
{
end_op();
return -1;
}
} else {
if((ip = namei(path)) == 0){
}
else
{
if ((ip = namei(path)) == 0)
{
end_op();
return -1;
}
ilock(ip);
if(ip->type == T_DIR && omode != O_RDONLY){
if (ip->type == T_DIR && omode != O_RDONLY)
{
iunlockput(ip);
end_op();
return -1;
}
}
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV))
{
iunlockput(ip);
end_op();
return -1;
}
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
if(f)
if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0)
{
if (f)
fileclose(f);
iunlockput(ip);
end_op();
return -1;
}
if(ip->type == T_DEVICE){
if (ip->type == T_DEVICE)
{
f->type = FD_DEVICE;
f->major = ip->major;
} else {
}
else
{
f->type = FD_INODE;
f->off = 0;
}
@ -360,7 +302,8 @@ sys_open(void)
f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if((omode & O_TRUNC) && ip->type == T_FILE){
if ((omode & O_TRUNC) && ip->type == T_FILE)
{
itrunc(ip);
}
@ -377,7 +320,8 @@ sys_mkdir(void)
struct inode *ip;
begin_op();
if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
if (argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0)
{
end_op();
return -1;
}
@ -396,8 +340,9 @@ sys_mknod(void)
begin_op();
argint(1, &major);
argint(2, &minor);
if((argstr(0, path, MAXPATH)) < 0 ||
(ip = create(path, T_DEVICE, major, minor)) == 0){
if ((argstr(0, path, MAXPATH)) < 0 ||
(ip = create(path, T_DEVICE, major, minor)) == 0)
{
end_op();
return -1;
}
@ -406,31 +351,6 @@ sys_mknod(void)
return 0;
}
uint64
sys_chdir(void)
{
char path[MAXPATH];
struct inode *ip;
struct proc *p = myproc();
begin_op();
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
end_op();
return -1;
}
ilock(ip);
if(ip->type != T_DIR){
iunlockput(ip);
end_op();
return -1;
}
iunlock(ip);
iput(p->cwd);
end_op();
p->cwd = ip;
return 0;
}
uint64
sys_exec(void)
{
@ -439,37 +359,42 @@ sys_exec(void)
uint64 uargv, uarg;
argaddr(1, &uargv);
if(argstr(0, path, MAXPATH) < 0) {
if (argstr(0, path, MAXPATH) < 0)
{
return -1;
}
memset(argv, 0, sizeof(argv));
for(i=0;; i++){
if(i >= NELEM(argv)){
for (i = 0;; i++)
{
if (i >= NELEM(argv))
{
goto bad;
}
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
if (fetchaddr(uargv + sizeof(uint64) * i, (uint64 *)&uarg) < 0)
{
goto bad;
}
if(uarg == 0){
if (uarg == 0)
{
argv[i] = 0;
break;
}
argv[i] = kalloc();
if(argv[i] == 0)
if (argv[i] == 0)
goto bad;
if(fetchstr(uarg, argv[i], PGSIZE) < 0)
if (fetchstr(uarg, argv[i], PGSIZE) < 0)
goto bad;
}
int ret = exec(path, argv);
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
kfree(argv[i]);
return ret;
bad:
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
bad:
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
kfree(argv[i]);
return -1;
}
@ -483,18 +408,20 @@ sys_pipe(void)
struct proc *p = myproc();
argaddr(0, &fdarray);
if(pipealloc(&rf, &wf) < 0)
if (pipealloc(&rf, &wf) < 0)
return -1;
fd0 = -1;
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
if(fd0 >= 0)
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0)
{
if (fd0 >= 0)
p->ofile[fd0] = 0;
fileclose(rf);
fileclose(wf);
return -1;
}
if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
if (copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(fd0)) < 0 ||
copyout(p->pagetable, fdarray + sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0)
{
p->ofile[fd0] = 0;
p->ofile[fd1] = 0;
fileclose(rf);