aboutsummaryrefslogtreecommitdiff
path: root/pk/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'pk/file.c')
-rw-r--r--pk/file.c102
1 files changed, 87 insertions, 15 deletions
diff --git a/pk/file.c b/pk/file.c
index 0c9c96a..b087920 100644
--- a/pk/file.c
+++ b/pk/file.c
@@ -2,15 +2,19 @@
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include "file.h"
#include "pk.h"
#include "frontend.h"
#include "vm.h"
+#include "devicetree.h"
+#include "sbi.h"
+#include "mcall.h"
#define MAX_FDS 128
static file_t* fds[MAX_FDS];
#define MAX_FILES 128
-file_t files[MAX_FILES] = {[0 ... MAX_FILES-1] = {-1,0}};
+file_t files[MAX_FILES] = {0};
void file_incref(file_t* f)
{
@@ -22,11 +26,13 @@ void file_decref(file_t* f)
{
if (atomic_add(&f->refcnt, -1) == 2)
{
- int kfd = f->kfd;
+ enum file_type typ = f->typ;
+ int kfd = ((host_file_t *) f)->kfd;
mb();
atomic_set(&f->refcnt, 0);
- frontend_syscall(SYS_close, kfd, 0, 0, 0, 0, 0, 0);
+ if (typ == FILE_HOST)
+ frontend_syscall(SYS_close, kfd, 0, 0, 0, 0, 0, 0);
}
}
@@ -55,9 +61,10 @@ void file_init()
{
// create stdin, stdout, stderr and FDs 0-2
for (int i = 0; i < 3; i++) {
- file_t* f = file_get_free();
+ host_file_t* f = (host_file_t *) file_get_free();
+ f->typ = FILE_HOST;
f->kfd = i;
- file_dup(f);
+ file_dup((file_t *) f);
}
}
@@ -82,9 +89,38 @@ file_t* file_open(const char* fn, int flags, int mode)
return file_openat(AT_FDCWD, fn, flags, mode);
}
-file_t* file_openat(int dirfd, const char* fn, int flags, int mode)
+device_t *device_open(const char *name, int flags)
+{
+ struct fdt_table_entry *entry;
+ device_t *dev;
+ int retval;
+
+ entry = fdt_find_device(name, 0);
+ if (entry == NULL)
+ return NULL;
+
+ // check permissions
+ if ((entry->prot & PROT_READ) == 0) {
+ debug_printk("insufficient permissions to access device %s\n", name);
+ return NULL;
+ }
+
+ if (flags != O_RDONLY && (entry->prot & PROT_WRITE) == 0) {
+ debug_printk("device %s is read only\n", name);
+ return NULL;
+ }
+
+ dev = (device_t *) file_get_free();
+ dev->typ = FILE_DEVICE;
+ dev->base = entry->base;
+ dev->size = entry->size;
+
+ return dev;
+}
+
+host_file_t *host_file_openat(int dirfd, const char *fn, int flags, int mode)
{
- file_t* f = file_get_free();
+ host_file_t* f = (host_file_t *) file_get_free();
if (f == NULL)
return ERR_PTR(-ENOMEM);
@@ -92,16 +128,24 @@ file_t* file_openat(int dirfd, const char* fn, int flags, int mode)
long ret = frontend_syscall(SYS_openat, dirfd, (long)fn, fn_size, flags, mode, 0, 0);
if (ret >= 0)
{
+ f->typ = FILE_HOST;
f->kfd = ret;
return f;
}
else
{
- file_decref(f);
+ file_decref((file_t *) f);
return ERR_PTR(ret);
}
}
+file_t* file_openat(int dirfd, const char* fn, int flags, int mode)
+{
+ if (strncmp("/dev/", fn, 5) == 0)
+ return (file_t *) device_open(fn + 5, flags);
+ return (file_t *) host_file_openat(dirfd, fn, flags, mode);
+}
+
int fd_close(int fd)
{
file_t* f = file_get(fd);
@@ -118,39 +162,67 @@ int fd_close(int fd)
ssize_t file_read(file_t* f, void* buf, size_t size)
{
populate_mapping(buf, size, PROT_WRITE);
- return frontend_syscall(SYS_read, f->kfd, (uintptr_t)buf, size, 0, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_read, hf->kfd, (uintptr_t)buf, size, 0, 0, 0, 0);
+ }
+ panic("read not supported on device file\n");
}
ssize_t file_pread(file_t* f, void* buf, size_t size, off_t offset)
{
populate_mapping(buf, size, PROT_WRITE);
- return frontend_syscall(SYS_pread, f->kfd, (uintptr_t)buf, size, offset, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_pread, hf->kfd, (uintptr_t)buf, size, offset, 0, 0, 0);
+ }
+ panic("pread not supported on device file\n");
}
ssize_t file_write(file_t* f, const void* buf, size_t size)
{
populate_mapping(buf, size, PROT_READ);
- return frontend_syscall(SYS_write, f->kfd, (uintptr_t)buf, size, 0, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_write, hf->kfd, (uintptr_t)buf, size, 0, 0, 0, 0);
+ }
+ panic("write not supported on device file\n");
}
ssize_t file_pwrite(file_t* f, const void* buf, size_t size, off_t offset)
{
populate_mapping(buf, size, PROT_READ);
- return frontend_syscall(SYS_pwrite, f->kfd, (uintptr_t)buf, size, offset, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_pwrite, hf->kfd, (uintptr_t)buf, size, offset, 0, 0, 0);
+ }
+ panic("pwrite not supported on device file\n");
}
int file_stat(file_t* f, struct stat* s)
{
populate_mapping(s, sizeof(*s), PROT_WRITE);
- return frontend_syscall(SYS_fstat, f->kfd, (uintptr_t)s, 0, 0, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_fstat, hf->kfd, (uintptr_t)s, 0, 0, 0, 0, 0);
+ }
+ panic("stat not supported on device file\n");
}
int file_truncate(file_t* f, off_t len)
{
- return frontend_syscall(SYS_ftruncate, f->kfd, len, 0, 0, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_ftruncate, hf->kfd, len, 0, 0, 0, 0, 0);
+ }
+ panic("stat not supported on device file\n");
}
ssize_t file_lseek(file_t* f, size_t ptr, int dir)
{
- return frontend_syscall(SYS_lseek, f->kfd, ptr, dir, 0, 0, 0, 0);
+ if (f->typ == FILE_HOST) {
+ host_file_t *hf = (host_file_t *) f;
+ return frontend_syscall(SYS_lseek, hf->kfd, ptr, dir, 0, 0, 0, 0);
+ }
+ panic("stat not supported on device file\n");
}