2011-12-11 03:34:10 +04:00
|
|
|
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
|
|
|
*
|
|
|
|
* Syscall Tables
|
|
|
|
*
|
2011-03-30 06:08:56 +04:00
|
|
|
*/
|
|
|
|
#include <system.h>
|
2011-12-09 01:25:48 +04:00
|
|
|
#include <process.h>
|
2011-12-15 05:06:11 +04:00
|
|
|
#include <logging.h>
|
2012-01-25 04:40:25 +04:00
|
|
|
#include <fs.h>
|
|
|
|
#include <pipe.h>
|
2012-01-27 08:46:18 +04:00
|
|
|
#include <version.h>
|
2012-02-06 04:12:50 +04:00
|
|
|
#include <shm.h>
|
2013-03-14 08:55:25 +04:00
|
|
|
#include <utsname.h>
|
|
|
|
|
|
|
|
static char hostname[256];
|
|
|
|
static size_t hostname_len = 0;
|
|
|
|
|
2011-04-12 01:45:15 +04:00
|
|
|
/*
|
|
|
|
* System calls themselves
|
|
|
|
*/
|
|
|
|
|
2011-04-18 02:44:29 +04:00
|
|
|
void validate(void * ptr) {
|
2013-03-18 11:52:12 +04:00
|
|
|
if (validate_safe(ptr)) {
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(ERROR, "SEGFAULT: Invalid pointer passed to syscall. (0x%x < 0x%x)", (uintptr_t)ptr, current_process->image.entry);
|
2011-04-18 02:44:29 +04:00
|
|
|
HALT_AND_CATCH_FIRE("Segmentation fault", NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-18 11:52:12 +04:00
|
|
|
int validate_safe(void * ptr) {
|
|
|
|
if (ptr && (uintptr_t)ptr < current_process->image.entry) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-12 01:45:15 +04:00
|
|
|
/*
|
2012-01-25 10:19:52 +04:00
|
|
|
* print something to the debug terminal (serial)
|
2011-04-12 01:45:15 +04:00
|
|
|
*/
|
2011-03-30 06:08:56 +04:00
|
|
|
static int print(char * s) {
|
2011-04-18 02:44:29 +04:00
|
|
|
validate((void *)s);
|
2012-11-29 11:05:19 +04:00
|
|
|
kprintf("%s", s);
|
2011-04-09 00:27:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-12 01:45:15 +04:00
|
|
|
/*
|
|
|
|
* Exit the current task.
|
|
|
|
* DOES NOT RETURN!
|
|
|
|
*/
|
2011-04-09 00:27:12 +04:00
|
|
|
static int exit(int retval) {
|
|
|
|
/* Deschedule the current task */
|
2011-04-09 01:26:34 +04:00
|
|
|
task_exit(retval);
|
2011-04-09 00:27:12 +04:00
|
|
|
while (1) { };
|
|
|
|
return retval;
|
2011-03-30 06:08:56 +04:00
|
|
|
}
|
|
|
|
|
2011-04-17 05:01:04 +04:00
|
|
|
static int read(int fd, char * ptr, int len) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2011-04-17 05:01:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
if (current_process->fds->entries[fd] == NULL) {
|
2012-01-25 10:19:52 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2011-04-18 02:44:29 +04:00
|
|
|
validate(ptr);
|
2012-02-17 00:31:40 +04:00
|
|
|
fs_node_t * node = current_process->fds->entries[fd];
|
2011-04-17 05:01:04 +04:00
|
|
|
uint32_t out = read_fs(node, node->offset, len, (uint8_t *)ptr);
|
|
|
|
node->offset += out;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2013-03-19 10:57:40 +04:00
|
|
|
static int ioctl(int fd, int request, void * argp) {
|
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (current_process->fds->entries[fd] == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
validate(argp);
|
|
|
|
fs_node_t * node = current_process->fds->entries[fd];
|
|
|
|
return ioctl_fs(node, request, argp);
|
|
|
|
}
|
|
|
|
|
2012-01-27 05:12:10 +04:00
|
|
|
static int readdir(int fd, int index, struct dirent * entry) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2012-01-27 05:12:10 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
if (current_process->fds->entries[fd] == NULL) {
|
2012-01-27 05:12:10 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
validate(entry);
|
2012-02-17 00:31:40 +04:00
|
|
|
fs_node_t * node = current_process->fds->entries[fd];
|
2012-01-27 05:12:10 +04:00
|
|
|
|
|
|
|
struct dirent * kentry = readdir_fs(node, (uint32_t)index);
|
|
|
|
if (!kentry) {
|
|
|
|
free(kentry);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(entry, kentry, sizeof(struct dirent));
|
|
|
|
free(kentry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-17 05:01:04 +04:00
|
|
|
static int write(int fd, char * ptr, int len) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if ((fd == 1 && !current_process->fds->entries[fd]) ||
|
|
|
|
(fd == 2 && !current_process->fds->entries[fd])) {
|
2012-02-13 02:45:23 +04:00
|
|
|
for (uint32_t i = 0; i < (uint32_t)len; ++i) {
|
2012-11-29 11:05:19 +04:00
|
|
|
kprintf("%c", ptr[i]);
|
2012-02-13 02:45:23 +04:00
|
|
|
}
|
2011-04-25 06:09:36 +04:00
|
|
|
return len;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2011-04-17 05:01:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
if (current_process->fds->entries[fd] == NULL) {
|
2012-01-25 10:19:52 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2011-04-18 02:44:29 +04:00
|
|
|
validate(ptr);
|
2012-02-17 00:31:40 +04:00
|
|
|
fs_node_t * node = current_process->fds->entries[fd];
|
2011-04-17 05:01:04 +04:00
|
|
|
uint32_t out = write_fs(node, node->offset, len, (uint8_t *)ptr);
|
|
|
|
node->offset += out;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2011-12-16 01:31:18 +04:00
|
|
|
static int wait(int child) {
|
2013-03-21 08:24:55 +04:00
|
|
|
process_t * volatile child_task;
|
|
|
|
if (child == 0) {
|
|
|
|
debug_print_process_tree();
|
2013-03-21 11:03:05 +04:00
|
|
|
child_task = process_get_first_child((process_t *)current_process);
|
2013-03-21 08:24:55 +04:00
|
|
|
} else if (child < 1) {
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(WARNING, "Process %d requested group wait, which we can not do!", getpid());
|
2011-12-16 01:31:18 +04:00
|
|
|
return 0;
|
2013-03-21 08:24:55 +04:00
|
|
|
} else {
|
|
|
|
child_task = process_from_pid(child);
|
2011-12-16 01:31:18 +04:00
|
|
|
}
|
2011-12-07 06:13:20 +04:00
|
|
|
/* If the child task doesn't exist, bail */
|
2012-01-25 10:19:52 +04:00
|
|
|
if (!child_task) {
|
2013-05-09 09:11:02 +04:00
|
|
|
debug_print(WARNING, "Tried to wait for non-existent process %d by pid %d", child, getpid());
|
2013-03-21 08:24:55 +04:00
|
|
|
return 0;
|
2012-01-25 10:19:52 +04:00
|
|
|
}
|
2013-03-21 08:24:55 +04:00
|
|
|
debug_print(NOTICE, "pid=%d waiting on pid=%d", current_process->id, child_task->id);
|
2011-12-07 06:13:20 +04:00
|
|
|
while (child_task->finished == 0) {
|
2012-02-01 05:27:38 +04:00
|
|
|
/* Add us to the wait queue for this child */
|
|
|
|
sleep_on(child_task->wait_queue);
|
2011-12-07 06:13:20 +04:00
|
|
|
}
|
|
|
|
/* Grab the child's return value */
|
2011-12-16 03:21:28 +04:00
|
|
|
int ret = child_task->status;
|
|
|
|
return ret;
|
2011-12-07 06:13:20 +04:00
|
|
|
}
|
|
|
|
|
2011-04-17 05:01:04 +04:00
|
|
|
static int open(const char * file, int flags, int mode) {
|
2011-04-18 02:44:29 +04:00
|
|
|
validate((void *)file);
|
2013-04-23 09:36:47 +04:00
|
|
|
debug_print(NOTICE, "open(%s) flags=0x%x; mode=0x%x", file, flags, mode);
|
2013-04-24 11:19:08 +04:00
|
|
|
fs_node_t * node = kopen((char *)file, flags);
|
|
|
|
if (!node && (flags & O_CREAT)) {
|
2013-04-23 09:36:47 +04:00
|
|
|
debug_print(NOTICE, "- file does not exist and create was requested.");
|
2012-01-31 10:16:09 +04:00
|
|
|
/* Um, make one */
|
2013-04-23 09:36:47 +04:00
|
|
|
if (!create_file_fs((char *)file, mode)) {
|
2013-04-24 11:19:08 +04:00
|
|
|
node = kopen((char *)file, flags);
|
2012-02-06 02:04:41 +04:00
|
|
|
}
|
2012-01-31 10:16:09 +04:00
|
|
|
}
|
2011-04-17 05:01:04 +04:00
|
|
|
if (!node) {
|
2013-04-23 09:36:47 +04:00
|
|
|
debug_print(NOTICE, "File does not exist; someone should be setting errno?");
|
2011-04-17 05:01:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
node->offset = 0;
|
2012-05-17 04:51:37 +04:00
|
|
|
int fd = process_append_fd((process_t *)current_process, node);
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(INFO, "[open] pid=%d %s -> %d", getpid(), file, fd);
|
2012-05-17 04:51:37 +04:00
|
|
|
return fd;
|
2011-04-17 05:01:04 +04:00
|
|
|
}
|
|
|
|
|
2013-03-22 22:58:22 +04:00
|
|
|
static int access(const char * file, int flags) {
|
|
|
|
validate((void *)file);
|
2013-04-23 09:36:47 +04:00
|
|
|
debug_print(INFO, "access(%s, 0x%x) from pid=%d", file, flags, getpid());
|
2013-03-22 22:58:22 +04:00
|
|
|
fs_node_t * node = kopen((char *)file, 0);
|
|
|
|
if (!node) return -1;
|
|
|
|
close_fs(node);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-17 05:01:04 +04:00
|
|
|
static int close(int fd) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2011-04-17 05:01:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
close_fs(current_process->fds->entries[fd]);
|
2011-04-17 05:01:04 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-18 03:28:40 +04:00
|
|
|
static int sys_sbrk(int size) {
|
2011-12-09 01:25:48 +04:00
|
|
|
uintptr_t ret = current_process->image.heap;
|
2012-01-19 06:12:04 +04:00
|
|
|
uintptr_t i_ret = ret;
|
|
|
|
while (ret % 0x1000) {
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
current_process->image.heap += (ret - i_ret) + size;
|
2011-12-09 01:25:48 +04:00
|
|
|
while (current_process->image.heap > current_process->image.heap_actual) {
|
|
|
|
current_process->image.heap_actual += 0x1000;
|
2012-01-19 06:12:04 +04:00
|
|
|
assert(current_process->image.heap_actual % 0x1000 == 0);
|
2011-12-09 01:25:48 +04:00
|
|
|
alloc_frame(get_page(current_process->image.heap_actual, 1, current_directory), 0, 1);
|
2011-04-18 03:28:40 +04:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-02-16 08:56:16 +04:00
|
|
|
static int sys_getpid() {
|
|
|
|
/* The user actually wants the pid of the originating thread (which can be us). */
|
2012-02-16 11:06:44 +04:00
|
|
|
if (current_process->group) {
|
|
|
|
return current_process->group;
|
|
|
|
} else {
|
|
|
|
/* We are the leader */
|
|
|
|
return current_process->id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Actual getpid() */
|
|
|
|
static int gettid() {
|
|
|
|
return getpid();
|
2012-02-16 08:56:16 +04:00
|
|
|
}
|
|
|
|
|
2011-04-17 22:26:31 +04:00
|
|
|
static int execve(const char * filename, char *const argv[], char *const envp[]) {
|
2011-04-18 02:44:29 +04:00
|
|
|
validate((void *)argv);
|
|
|
|
validate((void *)filename);
|
|
|
|
validate((void *)envp);
|
2013-04-23 12:14:33 +04:00
|
|
|
debug_print(NOTICE, "%d = exec(%s, ...)", current_process->id, filename);
|
2012-10-08 07:46:35 +04:00
|
|
|
int argc = 0, envc = 0;
|
|
|
|
while (argv[argc]) { ++argc; }
|
|
|
|
if (envp) {
|
|
|
|
while (envp[envc]) { ++envc; }
|
2011-04-17 22:26:31 +04:00
|
|
|
}
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(INFO, "Allocating space for arguments...");
|
2013-03-19 08:52:45 +04:00
|
|
|
char ** argv_ = malloc(sizeof(char *) * (argc + 1));
|
2012-10-08 07:46:35 +04:00
|
|
|
for (int j = 0; j < argc; ++j) {
|
2011-04-18 02:44:29 +04:00
|
|
|
argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char));
|
|
|
|
memcpy(argv_[j], argv[j], strlen(argv[j]) + 1);
|
|
|
|
}
|
2013-03-19 08:52:45 +04:00
|
|
|
argv_[argc] = 0;
|
2012-10-08 07:46:35 +04:00
|
|
|
char ** envp_;
|
|
|
|
if (envp && envc) {
|
|
|
|
envp_ = malloc(sizeof(char *) * (envc + 1));
|
|
|
|
for (int j = 0; j < envc; ++j) {
|
|
|
|
envp_[j] = malloc((strlen(envp[j]) + 1) * sizeof(char));
|
|
|
|
memcpy(envp_[j], envp[j], strlen(envp[j]) + 1);
|
|
|
|
}
|
|
|
|
envp_[envc] = 0;
|
|
|
|
} else {
|
|
|
|
envp_ = malloc(sizeof(char *));
|
|
|
|
envp_[0] = NULL;
|
|
|
|
}
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(INFO,"Releasing all shmem regions...");
|
2012-02-09 02:00:51 +04:00
|
|
|
shm_release_all((process_t *)current_process);
|
|
|
|
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(INFO,"Executing...");
|
2011-04-17 22:26:31 +04:00
|
|
|
/* Discard envp */
|
2012-10-08 07:46:35 +04:00
|
|
|
exec((char *)filename, argc, (char **)argv_, (char **)envp_);
|
2011-04-17 22:26:31 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-04-30 04:54:07 +04:00
|
|
|
static int getgraphicsaddress() {
|
2012-09-18 09:46:43 +04:00
|
|
|
return (int)lfb_get_address();
|
2011-04-30 04:54:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int seek(int fd, int offset, int whence) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2011-04-30 04:54:07 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (fd < 3) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (whence == 0) {
|
2012-02-17 00:31:40 +04:00
|
|
|
current_process->fds->entries[fd]->offset = offset;
|
2011-04-30 04:54:07 +04:00
|
|
|
} else if (whence == 1) {
|
2012-02-17 00:31:40 +04:00
|
|
|
current_process->fds->entries[fd]->offset += offset;
|
2011-04-30 04:54:07 +04:00
|
|
|
} else if (whence == 2) {
|
2012-02-17 00:31:40 +04:00
|
|
|
current_process->fds->entries[fd]->offset = current_process->fds->entries[fd]->length + offset;
|
2011-04-30 04:54:07 +04:00
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
return current_process->fds->entries[fd]->offset;
|
2011-04-30 04:54:07 +04:00
|
|
|
}
|
|
|
|
|
2013-04-23 09:36:47 +04:00
|
|
|
static int stat_node(fs_node_t * fn, uintptr_t st) {
|
|
|
|
struct stat * f = (struct stat *)st;
|
|
|
|
if (!fn) {
|
|
|
|
memset(f, 0x00, sizeof(struct stat));
|
|
|
|
debug_print(INFO, "stat: This file doesn't exist");
|
2012-01-27 13:12:29 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
f->st_dev = 0;
|
|
|
|
f->st_ino = fn->inode;
|
|
|
|
|
|
|
|
uint32_t flags = 0;
|
|
|
|
if (fn->flags & FS_FILE) { flags |= _IFREG; }
|
|
|
|
if (fn->flags & FS_DIRECTORY) { flags |= _IFDIR; }
|
|
|
|
if (fn->flags & FS_CHARDEVICE) { flags |= _IFCHR; }
|
|
|
|
if (fn->flags & FS_BLOCKDEVICE) { flags |= _IFBLK; }
|
|
|
|
if (fn->flags & FS_PIPE) { flags |= _IFIFO; }
|
|
|
|
if (fn->flags & FS_SYMLINK) { flags |= _IFLNK; }
|
|
|
|
|
|
|
|
f->st_mode = fn->mask | flags;
|
|
|
|
f->st_nlink = 0;
|
|
|
|
f->st_uid = fn->uid;
|
|
|
|
f->st_gid = fn->gid;
|
|
|
|
f->st_rdev = 0;
|
|
|
|
f->st_size = fn->length;
|
|
|
|
|
2012-12-10 04:59:55 +04:00
|
|
|
f->st_atime = fn->atime;
|
|
|
|
f->st_mtime = fn->mtime;
|
|
|
|
f->st_ctime = fn->ctime;
|
|
|
|
|
2013-03-22 22:58:22 +04:00
|
|
|
if (fn->get_size) {
|
|
|
|
f->st_size = fn->get_size(fn);
|
2012-01-31 10:16:09 +04:00
|
|
|
}
|
|
|
|
|
2011-04-30 04:54:07 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-23 09:36:47 +04:00
|
|
|
static int stat_file(char * file, uintptr_t st) {
|
|
|
|
int result;
|
|
|
|
validate((void *)file);
|
|
|
|
validate((void *)st);
|
|
|
|
fs_node_t * fn = kopen(file, 0);
|
|
|
|
result = stat_node(fn, st);
|
|
|
|
if (fn) {
|
|
|
|
close_fs(fn);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:14:33 +04:00
|
|
|
static int sys_chmod(char * file, int mode) {
|
|
|
|
int result;
|
|
|
|
validate((void *)file);
|
|
|
|
fs_node_t * fn = kopen(file, 0);
|
|
|
|
if (fn) {
|
|
|
|
result = chmod_fs(fn, mode);
|
|
|
|
close_fs(fn);
|
|
|
|
return result;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 09:36:47 +04:00
|
|
|
static int stat(int fd, uintptr_t st) {
|
|
|
|
validate((void *)st);
|
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fs_node_t * fn = current_process->fds->entries[fd];
|
|
|
|
return stat_node(fn, st);
|
|
|
|
}
|
|
|
|
|
2011-04-30 06:41:29 +04:00
|
|
|
static int setgraphicsoffset(int rows) {
|
|
|
|
bochs_set_y_offset(rows);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-16 23:16:20 +04:00
|
|
|
static int getgraphicswidth() {
|
2012-09-18 09:46:43 +04:00
|
|
|
return lfb_resolution_x;
|
2011-12-16 23:16:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int getgraphicsheight() {
|
2012-09-18 09:46:43 +04:00
|
|
|
return lfb_resolution_y;
|
2011-12-16 23:16:20 +04:00
|
|
|
}
|
|
|
|
|
VESA mode switching support.
BIOS execution is provided through the `v8086` module, which provides
software emulation of an 8086 processor. It is not currently working
with some BIOSes and may (read: probably will be) replaced with another
emulator (x86emu comes to mind) at some point in the near future. In the
meantime, the default video mode for QEMU works with this and it's
enough to get us on real VESA instead of fake VBE. The `bochs` module
will be renamed in a future commit. Userspace programs have been
adjusted to work at bitrates other than 32 *POORLY*. If you write pixels
left-to-right, they should work fine. They only work with 24-bpp
otherwise, and then you need to be careful of what pixels you are
writing when, or you will overwrite things in other pixels.
You may pass a commandline argument like the following to set display
modes:
vid=vesa,1024,768
Or for stranger modes under QEMU or Bochs, use the bochs VBE
initializer:
vid=bochs,1280,720
Note that the address of the linear framebuffer is still found via
hackish probing instead of PCI or trusting the VBE information, so if
you have things in the wrong memory ranges (0xE0000000+), be prepared to
have them get read.
Once again, this entire commit is a massive hack. I am happy that it
worked, and I will continue to make it less hacky, but in the meantime,
this is what we've got.
Happy holidays.
2011-12-25 10:40:40 +04:00
|
|
|
static int getgraphicsdepth() {
|
2012-09-18 09:46:43 +04:00
|
|
|
return lfb_resolution_b;
|
VESA mode switching support.
BIOS execution is provided through the `v8086` module, which provides
software emulation of an 8086 processor. It is not currently working
with some BIOSes and may (read: probably will be) replaced with another
emulator (x86emu comes to mind) at some point in the near future. In the
meantime, the default video mode for QEMU works with this and it's
enough to get us on real VESA instead of fake VBE. The `bochs` module
will be renamed in a future commit. Userspace programs have been
adjusted to work at bitrates other than 32 *POORLY*. If you write pixels
left-to-right, they should work fine. They only work with 24-bpp
otherwise, and then you need to be careful of what pixels you are
writing when, or you will overwrite things in other pixels.
You may pass a commandline argument like the following to set display
modes:
vid=vesa,1024,768
Or for stranger modes under QEMU or Bochs, use the bochs VBE
initializer:
vid=bochs,1280,720
Note that the address of the linear framebuffer is still found via
hackish probing instead of PCI or trusting the VBE information, so if
you have things in the wrong memory ranges (0xE0000000+), be prepared to
have them get read.
Once again, this entire commit is a massive hack. I am happy that it
worked, and I will continue to make it less hacky, but in the meantime,
this is what we've got.
Happy holidays.
2011-12-25 10:40:40 +04:00
|
|
|
}
|
|
|
|
|
2012-01-25 04:40:25 +04:00
|
|
|
static int mkpipe() {
|
2012-01-25 10:19:52 +04:00
|
|
|
fs_node_t * node = make_pipe(4096 * 2);
|
2012-01-25 04:40:25 +04:00
|
|
|
return process_append_fd((process_t *)current_process, node);
|
|
|
|
}
|
|
|
|
|
2012-01-25 05:06:07 +04:00
|
|
|
static int dup2(int old, int new) {
|
|
|
|
process_move_fd((process_t *)current_process, old, new);
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2012-01-27 08:46:18 +04:00
|
|
|
static int getuid() {
|
|
|
|
return current_process->user;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setuid(user_t new_uid) {
|
2012-01-27 09:11:43 +04:00
|
|
|
if (current_process->user == USER_ROOT_UID) {
|
2012-01-27 08:46:18 +04:00
|
|
|
current_process->user = new_uid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kernel_name_XXX(char * buffer) {
|
|
|
|
char version_number[1024];
|
|
|
|
sprintf(version_number, __kernel_version_format,
|
|
|
|
__kernel_version_major,
|
|
|
|
__kernel_version_minor,
|
|
|
|
__kernel_version_lower,
|
|
|
|
__kernel_version_suffix);
|
|
|
|
return sprintf(buffer, "%s %s %s %s %s %s",
|
|
|
|
__kernel_name,
|
|
|
|
version_number,
|
|
|
|
__kernel_version_codename,
|
|
|
|
__kernel_build_date,
|
|
|
|
__kernel_build_time,
|
|
|
|
__kernel_arch);
|
|
|
|
}
|
|
|
|
|
2013-03-14 08:55:25 +04:00
|
|
|
static int uname(struct utsname * name) {
|
|
|
|
validate((void *)name);
|
|
|
|
char version_number[256];
|
|
|
|
sprintf(version_number, __kernel_version_format,
|
|
|
|
__kernel_version_major,
|
|
|
|
__kernel_version_minor,
|
|
|
|
__kernel_version_lower,
|
|
|
|
__kernel_version_suffix);
|
|
|
|
char version_string[256];
|
|
|
|
sprintf(version_string, "%s %s %s",
|
|
|
|
__kernel_version_codename,
|
|
|
|
__kernel_build_date,
|
|
|
|
__kernel_build_time);
|
|
|
|
strcpy(name->sysname, __kernel_name);
|
|
|
|
strcpy(name->nodename, hostname);
|
|
|
|
strcpy(name->release, version_number);
|
|
|
|
strcpy(name->version, version_string);
|
|
|
|
strcpy(name->machine, __kernel_arch);
|
|
|
|
strcpy(name->domainname, "");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-08 12:40:44 +04:00
|
|
|
static int send_signal(pid_t process, uint32_t signal) {
|
|
|
|
process_t * receiver = process_from_pid(process);
|
|
|
|
|
|
|
|
if (!receiver) {
|
|
|
|
/* Invalid pid */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (receiver->user != current_process->user && current_process->user != USER_ROOT_UID) {
|
|
|
|
/* No way in hell. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-02-13 04:47:01 +04:00
|
|
|
if (signal > NUMSIGNALS) {
|
2012-02-08 12:40:44 +04:00
|
|
|
/* Invalid signal */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (receiver->finished) {
|
|
|
|
/* Can't send signals to finished processes */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Append signal to list */
|
|
|
|
signal_t * sig = malloc(sizeof(signal_t));
|
|
|
|
sig->handler = (uintptr_t)receiver->signals.functions[signal];
|
|
|
|
sig->signum = signal;
|
|
|
|
memset(&sig->registers_before, 0x00, sizeof(regs_t));
|
|
|
|
|
2012-12-01 06:26:47 +04:00
|
|
|
if (!process_is_ready(receiver)) {
|
2012-02-08 12:40:44 +04:00
|
|
|
make_process_ready(receiver);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_insert(receiver->signal_queue, sig);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uintptr_t sys_signal(uint32_t signum, uintptr_t handler) {
|
2012-02-13 04:47:01 +04:00
|
|
|
if (signum > NUMSIGNALS) {
|
2012-02-08 12:40:44 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
uintptr_t old = current_process->signals.functions[signum];
|
|
|
|
current_process->signals.functions[signum] = handler;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2012-02-06 00:16:59 +04:00
|
|
|
/*
|
|
|
|
static void inspect_memory (uintptr_t vaddr) {
|
|
|
|
// Please use this scary hack of a function as infrequently as possible.
|
|
|
|
shmem_debug_frame(vaddr);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2012-09-29 11:38:45 +04:00
|
|
|
extern void ext2_disk_sync();
|
|
|
|
|
2012-01-27 09:11:43 +04:00
|
|
|
static int reboot() {
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(NOTICE, "[kernel] Reboot requested from process %d by user #%d", current_process->id, current_process->user);
|
2012-02-08 12:40:44 +04:00
|
|
|
if (current_process->user != USER_ROOT_UID) {
|
2012-01-27 09:11:43 +04:00
|
|
|
return -1;
|
|
|
|
} else {
|
2012-09-04 09:35:11 +04:00
|
|
|
debug_print(NOTICE, "[kernel] Good bye!");
|
2012-09-29 11:38:45 +04:00
|
|
|
ext2_disk_sync();
|
2012-01-27 09:11:43 +04:00
|
|
|
/* Goodbye, cruel world */
|
2012-09-29 11:38:45 +04:00
|
|
|
IRQ_OFF;
|
2012-01-27 09:11:43 +04:00
|
|
|
uint8_t out = 0x02;
|
|
|
|
while ((out & 0x02) != 0) {
|
|
|
|
out = inportb(0x64);
|
|
|
|
}
|
|
|
|
outportb(0x64, 0xFE); /* Reset */
|
|
|
|
STOP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-27 23:10:58 +04:00
|
|
|
static int chdir(char * newdir) {
|
|
|
|
char * path = canonicalize_path(current_process->wd_name, newdir);
|
|
|
|
fs_node_t * chd = kopen(path, 0);
|
|
|
|
if (chd) {
|
|
|
|
if ((chd->flags & FS_DIRECTORY) == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(current_process->wd_name);
|
|
|
|
current_process->wd_name = malloc(strlen(path) + 1);
|
|
|
|
memcpy(current_process->wd_name, path, strlen(path) + 1);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * getcwd(char * buf, size_t size) {
|
|
|
|
if (!buf) return NULL;
|
|
|
|
validate((void *)buf);
|
|
|
|
memcpy(buf, current_process->wd_name, min(size, strlen(current_process->wd_name) + 1));
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2012-01-30 22:10:53 +04:00
|
|
|
static int sethostname(char * new_hostname) {
|
|
|
|
if (current_process->user == USER_ROOT_UID) {
|
|
|
|
size_t len = strlen(new_hostname) + 1;
|
|
|
|
if (len > 256) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
hostname_len = len;
|
|
|
|
memcpy(hostname, new_hostname, hostname_len);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gethostname(char * buffer) {
|
|
|
|
memcpy(buffer, hostname, hostname_len);
|
|
|
|
return hostname_len;
|
|
|
|
}
|
|
|
|
|
2012-02-03 02:16:29 +04:00
|
|
|
static int mousedevice() {
|
|
|
|
extern fs_node_t * mouse_pipe;
|
|
|
|
return process_append_fd((process_t *)current_process, mouse_pipe);
|
|
|
|
}
|
|
|
|
|
2012-11-29 11:05:19 +04:00
|
|
|
static int open_serial(int device) {
|
|
|
|
return process_append_fd((process_t *)current_process, serial_device_create(device));
|
|
|
|
}
|
|
|
|
|
2012-02-06 02:04:41 +04:00
|
|
|
extern int mkdir_fs(char *name, uint16_t permission);
|
|
|
|
|
|
|
|
static int sys_mkdir(char * path, uint32_t mode) {
|
|
|
|
return mkdir_fs(path, 0777);
|
|
|
|
}
|
|
|
|
|
2012-02-09 06:59:34 +04:00
|
|
|
/**
|
|
|
|
* share_fd: Make a file descriptor available to another process.
|
|
|
|
*/
|
|
|
|
static uintptr_t share_fd(int fd, int pid) {
|
2012-02-17 00:31:40 +04:00
|
|
|
if (fd >= (int)current_process->fds->length || fd < 0) {
|
2012-02-09 06:59:34 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2012-02-17 00:31:40 +04:00
|
|
|
fs_node_t * fn = current_process->fds->entries[fd];
|
2012-02-09 06:59:34 +04:00
|
|
|
fn->shared_with = pid;
|
|
|
|
return (uintptr_t)fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get_fd: Retreive a file descriptor (by key == pointer to fs_node_t) from
|
|
|
|
* another proces.
|
|
|
|
*/
|
|
|
|
static int get_fd(uintptr_t fn) {
|
2012-02-13 04:47:01 +04:00
|
|
|
fs_node_t * node = (fs_node_t *)fn;
|
2012-02-17 00:31:40 +04:00
|
|
|
if (node->shared_with == current_process->id || node->shared_with == current_process->group) {
|
2012-02-09 06:59:34 +04:00
|
|
|
return process_append_fd((process_t *)current_process, node);
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-02 07:13:52 +04:00
|
|
|
/*
|
|
|
|
* Yield the rest of the quantum;
|
|
|
|
* useful for busy waiting and other such things
|
|
|
|
*/
|
|
|
|
static int yield() {
|
|
|
|
switch_task(1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-05-17 04:51:37 +04:00
|
|
|
/*
|
|
|
|
* System Function
|
|
|
|
*/
|
2012-09-04 09:35:11 +04:00
|
|
|
static int system_function(int fn, char ** args) {
|
2012-05-17 04:51:37 +04:00
|
|
|
/* System Functions are special debugging system calls */
|
|
|
|
if (current_process->user == USER_ROOT_UID) {
|
|
|
|
switch (fn) {
|
|
|
|
case 1:
|
|
|
|
/* Print memory information */
|
|
|
|
/* Future: /proc/meminfo */
|
|
|
|
kprintf("Memory used: %d\n", memory_use());
|
|
|
|
kprintf("Memory available: %d\n", memory_total());
|
|
|
|
return 0;
|
|
|
|
case 2:
|
|
|
|
/* Print process tree */
|
|
|
|
/* Future: /proc in general */
|
|
|
|
debug_print_process_tree();
|
|
|
|
return 0;
|
2012-05-31 15:52:47 +04:00
|
|
|
case 3:
|
|
|
|
ext2_disk_sync();
|
|
|
|
return 0;
|
2012-09-04 09:35:11 +04:00
|
|
|
case 4:
|
|
|
|
/* Request kernel output to file descriptor in arg0*/
|
|
|
|
kprintf("Setting output to file object in process %d's fd=%d!\n", getpid(), (int)args);
|
|
|
|
kprint_to_file = current_process->fds->entries[(int)args];
|
|
|
|
break;
|
2012-12-03 09:43:54 +04:00
|
|
|
case 5:
|
|
|
|
debug_print(INFO, "replacing process %d's file descriptors with null devices", getpid());
|
|
|
|
fs_node_t * nulldev = null_device_create();
|
|
|
|
while (current_process->fds->length < 3) {
|
|
|
|
process_append_fd((process_t *)current_process, nulldev);
|
|
|
|
}
|
|
|
|
current_process->fds->entries[0] = nulldev;
|
|
|
|
current_process->fds->entries[1] = nulldev;
|
|
|
|
current_process->fds->entries[2] = nulldev;
|
|
|
|
break;
|
2012-05-17 04:51:37 +04:00
|
|
|
default:
|
2012-09-04 09:35:11 +04:00
|
|
|
kprintf("Bad system function %d\n", fn);
|
2012-05-17 04:51:37 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1; /* Bad system function or access failure */
|
|
|
|
}
|
|
|
|
|
2012-12-11 08:28:31 +04:00
|
|
|
static int sleep(unsigned long seconds, unsigned long subseconds) {
|
|
|
|
/* Mark us as asleep until <some time period> */
|
|
|
|
sleep_until((process_t *)current_process, seconds, subseconds);
|
|
|
|
|
|
|
|
/* Switch without adding us to the queue */
|
|
|
|
switch_task(0);
|
|
|
|
|
|
|
|
if (seconds > timer_ticks || (seconds == timer_ticks && subseconds >= timer_subticks)) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sleep_rel(unsigned long seconds, unsigned long subseconds) {
|
|
|
|
unsigned long s, ss;
|
|
|
|
relative_time(seconds, subseconds, &s, &ss);
|
|
|
|
return sleep(s, ss);
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:14:33 +04:00
|
|
|
static int sys_umask(int mode) {
|
|
|
|
current_process->mask = mode & 0777;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sys_unlink(char * file) {
|
|
|
|
return unlink_fs(file);
|
|
|
|
}
|
|
|
|
|
2011-04-12 01:45:15 +04:00
|
|
|
/*
|
|
|
|
* System Call Internals
|
|
|
|
*/
|
2011-03-30 10:22:31 +04:00
|
|
|
static uintptr_t syscalls[] = {
|
2011-03-30 06:08:56 +04:00
|
|
|
/* System Call Table */
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&exit, /* 0 */
|
2011-04-17 05:01:04 +04:00
|
|
|
(uintptr_t)&print,
|
|
|
|
(uintptr_t)&open,
|
|
|
|
(uintptr_t)&read,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&write, /* 4 */
|
2011-04-17 22:26:31 +04:00
|
|
|
(uintptr_t)&close,
|
|
|
|
(uintptr_t)&gettimeofday,
|
|
|
|
(uintptr_t)&execve,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&fork, /* 8 */
|
2012-02-16 08:56:16 +04:00
|
|
|
(uintptr_t)&sys_getpid,
|
2011-04-18 03:28:40 +04:00
|
|
|
(uintptr_t)&sys_sbrk,
|
2011-04-30 04:54:07 +04:00
|
|
|
(uintptr_t)&getgraphicsaddress,
|
2013-03-14 08:55:25 +04:00
|
|
|
(uintptr_t)&uname, /* 12 */
|
2013-03-18 03:34:23 +04:00
|
|
|
(uintptr_t)&openpty,
|
2011-04-30 04:54:07 +04:00
|
|
|
(uintptr_t)&seek,
|
|
|
|
(uintptr_t)&stat,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&setgraphicsoffset, /* 16 */
|
2011-12-07 06:13:20 +04:00
|
|
|
(uintptr_t)&wait,
|
2011-12-16 23:16:20 +04:00
|
|
|
(uintptr_t)&getgraphicswidth,
|
|
|
|
(uintptr_t)&getgraphicsheight,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&getgraphicsdepth, /* 20 */
|
2012-01-25 04:40:25 +04:00
|
|
|
(uintptr_t)&mkpipe,
|
2012-01-25 05:06:07 +04:00
|
|
|
(uintptr_t)&dup2,
|
2012-01-27 08:46:18 +04:00
|
|
|
(uintptr_t)&getuid,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&setuid, /* 24 */
|
2012-01-27 08:46:18 +04:00
|
|
|
(uintptr_t)&kernel_name_XXX,
|
2012-01-27 09:11:43 +04:00
|
|
|
(uintptr_t)&reboot,
|
2012-01-27 05:12:10 +04:00
|
|
|
(uintptr_t)&readdir,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&chdir, /* 28 */
|
2012-01-27 23:10:58 +04:00
|
|
|
(uintptr_t)&getcwd,
|
2012-01-29 03:06:07 +04:00
|
|
|
(uintptr_t)&clone,
|
2012-01-30 22:10:53 +04:00
|
|
|
(uintptr_t)&sethostname,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&gethostname, /* 32 */
|
2012-02-03 02:16:29 +04:00
|
|
|
(uintptr_t)&mousedevice,
|
2012-02-06 02:04:41 +04:00
|
|
|
(uintptr_t)&sys_mkdir,
|
2012-02-06 00:16:59 +04:00
|
|
|
(uintptr_t)&shm_obtain,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&shm_release, /* 36 */
|
2012-02-08 12:40:44 +04:00
|
|
|
(uintptr_t)&send_signal,
|
|
|
|
(uintptr_t)&sys_signal,
|
2012-02-09 06:59:34 +04:00
|
|
|
(uintptr_t)&share_fd,
|
2012-07-07 08:16:19 +04:00
|
|
|
(uintptr_t)&get_fd, /* 40 */
|
2012-02-16 11:06:44 +04:00
|
|
|
(uintptr_t)&gettid,
|
2012-03-02 07:13:52 +04:00
|
|
|
(uintptr_t)&yield,
|
2012-05-17 04:51:37 +04:00
|
|
|
(uintptr_t)&system_function,
|
2012-11-29 11:05:19 +04:00
|
|
|
(uintptr_t)&open_serial, /* 44 */
|
2012-12-11 08:28:31 +04:00
|
|
|
(uintptr_t)&sleep,
|
|
|
|
(uintptr_t)&sleep_rel,
|
2013-03-19 10:57:40 +04:00
|
|
|
(uintptr_t)&ioctl,
|
2013-03-22 22:58:22 +04:00
|
|
|
(uintptr_t)&access, /* 48 */
|
2013-04-23 09:36:47 +04:00
|
|
|
(uintptr_t)&stat_file,
|
2013-04-23 12:14:33 +04:00
|
|
|
(uintptr_t)&sys_chmod,
|
|
|
|
(uintptr_t)&sys_umask,
|
|
|
|
(uintptr_t)&sys_unlink, /* 52 */
|
2012-01-25 04:40:25 +04:00
|
|
|
0
|
2011-03-30 06:08:56 +04:00
|
|
|
};
|
2012-01-25 04:40:25 +04:00
|
|
|
uint32_t num_syscalls;
|
2011-03-30 06:08:56 +04:00
|
|
|
|
2013-05-09 09:11:02 +04:00
|
|
|
typedef uint32_t (*scall_func)(unsigned int, ...);
|
2011-03-30 06:08:56 +04:00
|
|
|
|
2013-05-09 09:11:02 +04:00
|
|
|
void syscall_handler(struct regs * r) {
|
2011-03-30 06:08:56 +04:00
|
|
|
if (r->eax >= num_syscalls) {
|
|
|
|
return;
|
|
|
|
}
|
2012-10-15 06:53:16 +04:00
|
|
|
|
2011-03-30 10:22:31 +04:00
|
|
|
uintptr_t location = syscalls[r->eax];
|
2013-05-09 09:11:02 +04:00
|
|
|
if (!location) {
|
2012-10-15 06:53:16 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-29 03:06:07 +04:00
|
|
|
/* Update the syscall registers for this process */
|
|
|
|
current_process->syscall_registers = r;
|
2011-12-16 01:31:18 +04:00
|
|
|
|
2013-05-09 09:11:02 +04:00
|
|
|
/* Call the syscall function */
|
|
|
|
scall_func func = (scall_func)location;
|
|
|
|
uint32_t ret = func(r->ebx, r->ecx, r->edx, r->esi, r->edi);
|
|
|
|
|
|
|
|
if ((current_process->syscall_registers == r) ||
|
|
|
|
(location != (uintptr_t)&fork && location != (uintptr_t)&clone)) {
|
|
|
|
r->eax = ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void syscalls_install() {
|
|
|
|
for (num_syscalls = 0; syscalls[num_syscalls] != 0; ++num_syscalls);
|
|
|
|
debug_print(NOTICE, "Initializing syscall table with %d functions", num_syscalls);
|
|
|
|
isrs_install_handler(0x7F, &syscall_handler);
|
2011-03-30 06:08:56 +04:00
|
|
|
}
|
2013-05-09 09:11:02 +04:00
|
|
|
|