Initial changes for execve() support

This commit is contained in:
Bahadir Balban
2008-11-13 21:45:30 +02:00
parent 44c34026b2
commit d182b5b35a
21 changed files with 618 additions and 9 deletions

213
tasks/mm0/src/execve.c Normal file
View File

@@ -0,0 +1,213 @@
/*
* Program execution
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/ipcdefs.h>
#include <l4lib/types.h>
#include <l4/macros.h>
#include <l4/api/errno.h>
#include <lib/malloc.h>
#include <vm_area.h>
#include <syscalls.h>
#include <string.h>
#include <file.h>
#include <user.h>
#include <task.h>
/*
* Different from vfs_open(), which validates an already opened
* file descriptor, this call opens a new vfs file by the pager
* using the given path. The vnum handle and file length is returned
* since the pager uses this information to access file pages.
*/
int vfs_open_bypath(const char *pathname, unsigned long *vnum, unsigned long *length)
{
int err = 0;
struct tcb *vfs;
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
if (!(vfs = find_task(VFS_TID)))
return -ESRCH;
/*
* Copy string to vfs utcb.
*
* FIXME: There's a chance we're overwriting other tasks'
* ipc information that is on the vfs utcb.
*/
strcpy(vfs->utcb, pathname);
l4_save_ipcregs();
write_mr(L4SYS_ARG0, (unsigned long)vfs->utcb);
if ((err = l4_sendrecv(VFS_TID, VFS_TID,
L4_IPC_TAG_PAGER_OPEN_BYPATH)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
goto out;
}
/* Check if syscall was successful */
if ((err = l4_get_retval()) < 0) {
printf("%s: VFS open error: %d.\n",
__FUNCTION__, err);
goto out;
}
/* Read file information */
*vnum = read_mr(L4SYS_ARG0);
*length = read_mr(L4SYS_ARG1);
out:
l4_restore_ipcregs();
return err;
}
int do_execve(char *filename)
{
int err;
unsigned long vnum, length;
struct vm_file *f;
/* Get file info from vfs */
if ((err = vfs_open_bypath(filename, &vnum, &length)) < 0)
return err;
/* Create and get the file structure */
if (IS_ERR(f = do_open2(0, 0, vnum, length)))
return (int)f;
/* Determine file segments to be mapped */
/* See if an interpreter (dynamic linker) is needed */
/* Destroy all threads in the same thread group except group leader */
/* Release all task resources, do almost everything done in exit() */
/*
* Create new process address space. Start by mapping all
* static file segments. We will need brk() for bss.
*/
#if 0
TODO:
Dynamic Linking.
/* Find the interpreter executable file, if needed */
/*
* Map all dynamic linker file segments
* (should not clash with original executable
*/
/* Set up registers to run dynamic linker (exchange_registers()) */
/* Run the interpreter */
/*
* The interpreter:
* - May need some initial info (dyn sym tables) at a certain location
* - Will find necessary shared library files in userspace
* (will use open/read).
* - Map them into process address space via mmap()
* - Reinitialise references to symbols in the shared libraries
* - Jump to the entry point of main executable.
*/
#endif
return -1;
}
/*
* Copies a null-terminated ragged array (i.e. argv[0]) from userspace into
* buffer. If any page boundary is hit, unmaps previous page, validates and
* maps the new page.
*/
int copy_user_ragged(struct tcb *task, char *buf[], char *user[], int maxlength)
{
return 0;
}
/*
* Copy from one buffer to another. Stop if maxlength or
* a page boundary is hit.
*/
int strncpy_page(char *to, char *from, int maxlength)
{
int count = 0;
do {
if ((to[count] = from[count]) == '\0')
break;
count++;
} while (count < maxlength && !page_boundary(&from[count]));
if (page_boundary(&from[count]))
return -EFAULT;
if (count == maxlength)
return -E2BIG;
return 0;
}
/*
* Copies a userspace string into buffer. If a page boundary is hit,
* unmaps the previous page, validates and maps the new page
*/
int copy_user_string(struct tcb *task, char *buf, char *user, int maxlength)
{
int count = maxlength;
char *mapped = 0;
int copied = 0;
int err = 0;
/* Map the first page the user buffer is in */
if (!(mapped = pager_validate_map_user_range(task, user,
TILL_PAGE_ENDS(user),
VM_READ)))
return -EINVAL;
while ((err = strncpy_page(&buf[copied], mapped, count)) < 0) {
if (err == -E2BIG)
return err;
if (err == -EFAULT) {
pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped));
copied += TILL_PAGE_ENDS(mapped);
count -= TILL_PAGE_ENDS(mapped);
if (!(mapped =
pager_validate_map_user_range(task, user + copied,
TILL_PAGE_ENDS(user + copied),
VM_READ)))
return -EINVAL;
}
}
/* Unmap the final page */
pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped));
return 0;
}
int sys_execve(struct tcb *sender, char *pathname, char *argv[], char *envp[])
{
int err;
char *path = kzalloc(PATH_MAX);
/* Copy the executable path string */
if ((err = copy_user_string(sender, path, pathname, PATH_MAX)) < 0)
return err;
printf("%s: Copied pathname: %s\n", __FUNCTION__, path);
return do_execve(path);
}

View File

@@ -1,4 +1,6 @@
/*
* File read, write, open and close.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <init.h>
@@ -118,6 +120,62 @@ out:
return err;
}
/*
* Initialise a new file and the descriptor for it from given file data.
* Could be called by an actual task or a pager
*/
struct vm_file *do_open2(struct tcb *task, int fd, unsigned long vnum, unsigned long length)
{
struct vm_file *vmfile;
/* Is this an open by a task (as opposed to by the pager)? */
if (task) {
/* fd slot must be empty */
BUG_ON(task->files->fd[fd].vnum != 0);
BUG_ON(task->files->fd[fd].cursor != 0);
/* Assign vnum to given fd on the task */
task->files->fd[fd].vnum = vnum;
task->files->fd[fd].cursor = 0;
}
/* Check if that vm_file is already in the list */
list_for_each_entry(vmfile, &global_vm_files.list, list) {
/* Check whether it is a vfs file and if so vnums match. */
if ((vmfile->type & VM_FILE_VFS) &&
vm_file_to_vnum(vmfile) == vnum) {
/* Task opener? */
if (task)
/* Add a reference to it from the task */
task->files->fd[fd].vmfile = vmfile;
vmfile->openers++;
return vmfile;
}
}
/* Otherwise allocate a new one for this vnode */
if (IS_ERR(vmfile = vfs_file_create()))
return vmfile;
/* Initialise and add a reference to it from the task */
vm_file_to_vnum(vmfile) = vnum;
vmfile->length = length;
vmfile->vm_obj.pager = &file_pager;
/* Task opener? */
if (task)
task->files->fd[fd].vmfile = vmfile;
vmfile->openers++;
/* Add to file list */
global_add_vm_file(vmfile);
return vmfile;
}
/* Initialise a new file and the descriptor for it from given file data */
int do_open(struct tcb *task, int fd, unsigned long vnum, unsigned long length)
{

View File

@@ -40,6 +40,9 @@ int pager_validate_user_range(struct tcb *user, void *userptr, unsigned long siz
* Validates and maps the user virtual address range to the pager.
* Every virtual page needs to be mapped individually because it's
* not guaranteed pages are physically contiguous.
*
* FIXME: There's no logic here to make non-contiguous physical pages
* to get mapped virtually contiguous.
*/
void *pager_validate_map_user_range(struct tcb *user, void *userptr,
unsigned long size, unsigned int vm_flags)