296 lines
No EOL
7.1 KiB
C
Executable file
296 lines
No EOL
7.1 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 lock 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);
|
|
lock_init(&filesys_lock);
|
|
}
|
|
|
|
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;
|
|
lock_acquire (&filesys_lock);
|
|
bool return_code = filesys_create(filename, initial_size);
|
|
lock_release (&filesys_lock);
|
|
return return_code;
|
|
}
|
|
|
|
bool sys_remove(const char* filename) {
|
|
if (check_ptr(filename)) return 0;
|
|
lock_acquire (&filesys_lock);
|
|
bool return_code = filesys_remove(filename);
|
|
lock_release (&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;
|
|
}
|
|
|
|
lock_acquire (&filesys_lock);
|
|
file_opened = filesys_open(file);
|
|
//printf("File opened: %x\n", file_opened);
|
|
if (!file_opened) {
|
|
free(fd);
|
|
lock_release (&filesys_lock);
|
|
return -1;
|
|
}
|
|
|
|
fd->file = file_opened;
|
|
fd->fd = next_fd++;
|
|
//printf("Hash put: %x %d\n", file_opened, fd->fd);
|
|
hash_insert(&fd_table, &fd->elem);
|
|
lock_release (&filesys_lock);
|
|
return fd->fd;
|
|
}
|
|
|
|
int sys_filesize(int fd) {
|
|
lock_acquire (&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 == NULL) {
|
|
lock_release (&filesys_lock);
|
|
return -1;
|
|
}
|
|
|
|
int ret = file_length(file_d->file);
|
|
lock_release (&filesys_lock);
|
|
return ret;
|
|
}
|
|
|
|
void sys_seek(int fd, unsigned position) {
|
|
lock_acquire (&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_seek(file_d->file, position);
|
|
}
|
|
else
|
|
return;
|
|
|
|
lock_release (&filesys_lock);
|
|
}
|
|
|
|
unsigned sys_tell(int fd) {
|
|
lock_acquire (&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);
|
|
|
|
unsigned ret;
|
|
if(file_d && file_d->file) {
|
|
ret = file_tell(file_d->file);
|
|
}
|
|
else
|
|
ret = -1;
|
|
|
|
lock_release (&filesys_lock);
|
|
return ret;
|
|
}
|
|
|
|
void sys_close(int fd) {
|
|
lock_acquire (&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);
|
|
//printf("File close id: %x\n", file_d);
|
|
if(file_d && file_d->file) {
|
|
//printf("File closed: %x\n", file_d->file);
|
|
file_close(file_d->file);
|
|
hash_delete(&fd_table, &(file_d->elem));
|
|
free(file_d);
|
|
}
|
|
lock_release (&filesys_lock);
|
|
}
|
|
|
|
int sys_read(int fd, void *buffer, unsigned size) {
|
|
if (check_ptr(buffer)||check_ptr(buffer+size)) return -1;
|
|
lock_acquire (&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 ret = -1;
|
|
}
|
|
|
|
lock_release (&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) {
|
|
putbuf(buffer, size);
|
|
ret = size;
|
|
} else {
|
|
lock_acquire (&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 ret = -1;
|
|
lock_release (&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)
|
|
{
|
|
int status = process_wait(tid);
|
|
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);
|
|
} |