This repository has been archived on 2021-05-26. You can view files and clone it, but cannot push or open issues or pull requests.
OS/pintos-env/pintos/userprog/syscall.c

294 lines
No EOL
6.8 KiB
C
Executable file

#include "userprog/syscall.h"
#include <stdio.h>
#include <syscall-nr.h>
#include "threads/interrupt.h"
#include "threads/thread.h"
#include <string.h>
#include "userprog/process.h"
#include "threads/vaddr.h"
#include "userprog/pagedir.h"
#include "lib/kernel/hash.h"
#include "filesys/filesys.h"
#include "filesys/file.h"
typedef int (*handler) (uint32_t, uint32_t, uint32_t);
static handler syscall_vec[128];
static int sys_exit (int status);
static int sys_wait (tid_t tid);
static tid_t sys_exec (const char* file_name);
static void syscall_nop(void);
static void sys_halt(void);
bool sys_create(const char* filename, unsigned initial_size);
bool sys_remove(const char* filename);
int sys_open(const char* file);
int sys_filesize(int fd);
void sys_seek(int fd, unsigned position);
unsigned sys_tell(int fd);
void sys_close(int fd);
int sys_read(int fd, void *buffer, unsigned size);
int sys_write(int fd, const void *buffer, unsigned size);
static void syscall_handler (struct intr_frame *);
struct fd_item {
int fd;
struct file* file;
struct hash_elem elem;
};
int next_fd = 3;
struct hash fd_table;
struct semaphore filesys_lock;
static unsigned item_hash (const struct hash_elem* e, void* aux) {
struct fd_item* i = hash_entry(e, struct fd_item, elem);
return hash_int(i->fd);
}
static bool item_compare(const struct hash_elem* a, const struct hash_elem* b, void* aux) {
struct fd_item *i_a = hash_entry(a, struct fd_item, elem);
struct fd_item *i_b = hash_entry(b, struct fd_item, elem);
return i_a->fd < i_b->fd;
}
void
syscall_init (void)
{
intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
memset(syscall_vec, (int)&syscall_nop, 128);
syscall_vec[SYS_EXIT] = (handler)sys_exit;
syscall_vec[SYS_WAIT] = (handler)sys_wait;
syscall_vec[SYS_EXEC] = (handler)sys_exec;
syscall_vec[SYS_HALT] = (handler)sys_halt;
syscall_vec[SYS_CREATE] = (handler)sys_create;
syscall_vec[SYS_REMOVE] = (handler)sys_remove;
syscall_vec[SYS_OPEN] = (handler)sys_open;
syscall_vec[SYS_FILESIZE] = (handler)sys_filesize;
syscall_vec[SYS_SEEK] = (handler)sys_seek;
syscall_vec[SYS_TELL] = (handler)sys_tell;
syscall_vec[SYS_CLOSE] = (handler)sys_close;
syscall_vec[SYS_READ] = (handler)sys_read;
syscall_vec[SYS_WRITE] = (handler)sys_write;
hash_init(&fd_table, item_hash, item_compare, NULL);
sema_init(&filesys_lock, 1);
}
static bool check_ptr(const void* ptr) {
if (ptr == NULL || is_kernel_vaddr(ptr) ||
pagedir_get_page(thread_current()->pagedir, ptr) == NULL) {
sys_exit(-1);
}
return false;
}
static
void sys_halt(void) {
shutdown_power_off();
}
bool sys_create(const char* filename, unsigned initial_size) {
if (check_ptr(filename)) return 0;
sema_down (&filesys_lock);
bool return_code = filesys_create(filename, initial_size);
sema_up (&filesys_lock);
return return_code;
}
bool sys_remove(const char* filename) {
if (check_ptr(filename)) return 0;
sema_down (&filesys_lock);
bool return_code = filesys_remove(filename);
sema_up (&filesys_lock);
return return_code;
}
int sys_open(const char* file) {
if (check_ptr(file)) return -1;
struct file* file_opened;
struct fd_item* fd = malloc(sizeof(struct fd_item*));
if (!fd) {
return -1;
}
sema_down (&filesys_lock);
file_opened = filesys_open(file);
if (!file_opened) {
free(fd);
sema_up (&filesys_lock);
return -1;
}
fd->file = file_opened; //file save
fd->fd = next_fd++;
hash_insert(&fd_table, &fd->elem);
sema_up (&filesys_lock);
return fd->fd;
}
int sys_filesize(int fd) {
sema_down (&filesys_lock);
struct fd_item i;
i.fd = fd;
struct fd_item* file_d = hash_entry(hash_find(&fd_table, &i.elem), struct fd_item, elem);
if(file_d == NULL) {
sema_up (&filesys_lock);
return -1;
}
int ret = file_length(file_d->file);
sema_up (&filesys_lock);
return ret;
}
void sys_seek(int fd, unsigned position) {
sema_down (&filesys_lock);
struct fd_item i;
i.fd = fd;
struct fd_item* file_d = hash_entry(hash_find(&fd_table, &i.elem), struct fd_item, elem);
if(file_d && file_d->file) {
file_seek(file_d->file, position);
}
else
return;
sema_up (&filesys_lock);
}
unsigned sys_tell(int fd) {
sema_down (&filesys_lock);
struct fd_item i;
i.fd = fd;
struct fd_item* file_d = hash_entry(hash_find(&fd_table, &i.elem), struct fd_item, elem);
unsigned ret;
if(file_d && file_d->file) {
ret = file_tell(file_d->file);
}
else
ret = -1;
sema_up (&filesys_lock);
return ret;
}
void sys_close(int fd) {
sema_down (&filesys_lock);
struct fd_item i;
i.fd = fd;
struct hash_elem* h = hash_find(&fd_table, &i.elem);
if (h == NULL) sys_exit(-1);
struct fd_item* file_d = hash_entry(h, struct fd_item, elem);
if(file_d && file_d->file) {
file_close(file_d->file);
hash_delete(&fd_table, &(file_d->elem));
free(file_d);
}
sema_up (&filesys_lock);
}
int sys_read(int fd, void *buffer, unsigned size) {
if (check_ptr(buffer)||check_ptr(buffer+size)) return -1;
sema_down (&filesys_lock);
int ret;
if(fd == 0) {
return -1;
} else {
struct fd_item i;
i.fd = fd;
struct hash_elem* h = hash_find(&fd_table, &i.elem);
if (h == NULL) sys_exit(-1);
struct fd_item* file_d = hash_entry(h, struct fd_item, elem);
if(file_d && file_d->file) {
ret = file_read(file_d->file, buffer, size);
}
else // no such file or can't open
ret = -1;
}
sema_up (&filesys_lock);
return ret;
}
int sys_write(int fd, const void *buffer, unsigned size) {
unsigned i;
for (i = 0; i <= size; i++) {
if (check_ptr(buffer + size)) return -1;
}
int ret;
if(fd == 1) { // write to stdout
putbuf(buffer, size);
ret = size;
} else {
sema_down (&filesys_lock);
struct fd_item i;
i.fd = fd;
struct hash_elem* h = hash_find(&fd_table, &i.elem);
if (h == NULL) sys_exit(-1);
struct fd_item* file_d = hash_entry(h, struct fd_item, elem);
if(file_d && file_d->file) {
ret = file_write(file_d->file, buffer, size);
}
else // no such file or can't open
ret = -1;
sema_up (&filesys_lock);
}
return ret;
}
static void
syscall_nop(void) {
printf("Syscall not implemented");
}
static void
syscall_handler (struct intr_frame *f)
{
handler h;
int *p;
int ret;
p = f->esp;
h = syscall_vec[*p];
ret = h (*(p + 1), *(p + 2), *(p + 3));
f->eax = ret;
}
int
sys_exit (int status)
{
struct thread* t = thread_current();
t->exit_status = status;
thread_exit();
return -1;
}
int
sys_wait (tid_t tid)
{
//printf("system call wait\n");
int status = process_wait(tid);
//printf("wait has returned status(%d)\n", status);
return status;
}
tid_t
sys_exec (const char* file_name) {
if (file_name == NULL || is_kernel_vaddr(file_name) ||
pagedir_get_page(thread_current()->pagedir, file_name) == NULL) {
return -1;
}
return process_execute(file_name);
}