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

View File

@@ -33,12 +33,16 @@
#define page_align(addr) (((unsigned int)(addr)) & \
(~PAGE_MASK))
#define is_aligned(val, mask) (!(((unsigned long)val) & mask))
#define is_page_aligned(val) (!(((unsigned long)val) & PAGE_MASK))
#define is_aligned(val, mask) (!(((unsigned long)(val)) & mask))
#define is_page_aligned(val) (!(((unsigned long)(val)) & PAGE_MASK))
#define page_boundary(x) is_page_aligned(x)
/* Align to given size */
#define align(addr, size) (((unsigned int)(addr)) & (~(size-1)))
/* The bytes left until the end of the page that x is in */
#define TILL_PAGE_ENDS(x) (PAGE_SIZE - ((unsigned long)(x) & PAGE_MASK))
/* Extract page frame number from address and vice versa. */
#define __pfn(x) (((unsigned long)(x)) >> PAGE_BITS)
#define __pfn_to_addr(x) (((unsigned long)(x)) << PAGE_BITS)

View File

@@ -15,7 +15,7 @@ int sys_mkdir(struct tcb *sender, const char *pathname, unsigned int mode);
int sys_chdir(struct tcb *sender, const char *pathname);
/* Calls from pager that completes a posix call */
int pager_open_bypath(struct tcb *pager, char *pathname);
int pager_sys_open(struct tcb *sender, l4id_t opener, int fd);
int pager_sys_read(struct tcb *sender, unsigned long vnum, unsigned long f_offset,
unsigned long npages, void *pagebuf);

View File

@@ -98,6 +98,9 @@ void handle_fs_requests(void)
case L4_IPC_TAG_PAGER_OPEN:
ret = pager_sys_open(sender, (l4id_t)mr[0], (int)mr[1]);
break;
case L4_IPC_TAG_PAGER_OPEN_BYPATH:
ret = pager_open_bypath(sender, (char *)mr[0]);
break;
case L4_IPC_TAG_PAGER_WRITE:
ret = pager_sys_write(sender, (unsigned long)mr[0], (unsigned long)mr[1],
(unsigned long)mr[2], (void *)mr[3]);

View File

@@ -64,6 +64,48 @@ int pager_sys_open(struct tcb *pager, l4id_t opener, int fd)
return 0;
}
/* This is called when the pager needs to open a vfs file via its path */
int pager_open_bypath(struct tcb *pager, char *pathname)
{
struct pathdata *pdata;
struct tcb *task;
struct vnode *v;
int retval;
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
if (pager->tid != PAGER_TID)
return -EINVAL;
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
/* Parse path data */
if (IS_ERR(pdata = pathdata_parse(pathname,
alloca(strlen(pathname) + 1),
task)))
return (int)pdata;
/* Search the vnode by that path */
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
retval = (int)v;
goto out;
}
/*
* Write file information, they will
* be sent via the return reply.
*/
write_mr(L4SYS_ARG0, v->vnum);
write_mr(L4SYS_ARG1, v->size);
return 0;
out:
pathdata_destroy(pdata);
return retval;
}
/* Directories only for now */
void print_vnode(struct vnode *v)
{

View File

@@ -54,16 +54,22 @@ static inline void write_mr(unsigned int offset, unsigned int val)
* map-in the task utcb and read those arguments from there.
*/
static inline void copy_to_utcb(void *arg, int offset, int size)
static inline int copy_to_utcb(void *arg, int offset, int size)
{
BUG_ON(offset + size > PAGE_SIZE);
if (offset + size > PAGE_SIZE)
return -1;
memcpy(utcb_page + offset, arg, size);
return 0;
}
static inline void copy_from_utcb(void *buf, int offset, int size)
static inline int copy_from_utcb(void *buf, int offset, int size)
{
BUG_ON(offset + size > PAGE_SIZE);
if (offset + size > PAGE_SIZE)
return -1;
memcpy(buf, utcb_page + offset, size);
return 0;
}
#endif /* !__ASSEMBLY__ */

View File

@@ -59,5 +59,5 @@
#define L4_IPC_TAG_PAGER_UPDATE_STATS 45 /* Pager updates file stats in vfs */
#define L4_IPC_TAG_NOTIFY_FORK 46 /* Pager notifies vfs of process fork */
#define L4_IPC_TAG_NOTIFY_EXIT 47 /* Pager notifies vfs of process exit */
#define L4_IPC_TAG_PAGER_OPEN_BYPATH 48 /* Pager opens a vfs file by pathname */
#endif /* __IPCDEFS_H__ */

66
tasks/libposix/execve.c Normal file
View File

@@ -0,0 +1,66 @@
/*
* l4/posix glue for execve()
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/ipcdefs.h>
#include <l4lib/utcb.h>
#include <fcntl.h>
#include <l4/macros.h>
#include INC_GLUE(memory.h)
struct sys_execve_args {
char *path;
char **argv;
char **envp;
};
static inline int l4_execve(const char *pathname, char *const argv[], char *const envp[])
{
int err = 0;
write_mr(L4SYS_ARG0, (unsigned long)pathname);
write_mr(L4SYS_ARG1, (unsigned long)argv);
write_mr(L4SYS_ARG2, (unsigned long)envp);
/* Call pager with open() request. Check ipc error. */
if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_EXECVE)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
return err;
}
/* Check if syscall itself was successful */
if ((err = l4_get_retval()) < 0) {
printf("%s: OPEN Error: %d.\n", __FUNCTION__, err);
return err;
}
return err;
}
int execve(const char *pathname, char *const argv[], char *const envp[])
{
int ret;
ret = l4_execve(pathname, argv, envp);
/* If error, return positive error code */
if (ret < 0) {
errno = -ret;
return -1;
}
/* else return value */
return ret;
}

View File

@@ -16,6 +16,8 @@ int sys_lseek(struct tcb *sender, int fd, off_t offset, int whence);
int sys_close(struct tcb *sender, int fd);
int sys_fsync(struct tcb *sender, int fd);
int file_open(struct tcb *opener, int fd);
struct vm_file *do_open2(struct tcb *task, int fd, unsigned long vnum, unsigned long length);
int flush_file_pages(struct vm_file *f);
struct vfs_file_data {

View File

@@ -0,0 +1,61 @@
/*
* Definitions for Executable Linking Format
* Based on Portable Formats Specification v1.1
*
* Copyright (C) 2008 Bahadir Balban
*/
#ifndef __ELF_H__
#define __ELF_H__
#include <l4/types.h>
/* ELF identification indices */
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
/* Size of ELF identification field */
#define EI_NIDENT 16
/* Values for ELF identification fields */
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
/* Values for the ELF Class field */
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
/* Values for the ELF Data field */
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
struct elf_header {
u8 e_ident[EI_NIDENT]; /* ELF identification */
u16 e_type; /* Object file type */
u16 e_machine; /* Machine architecture */
u32 e_version; /* Object file version */
u32 e_entry; /* Virtual entry address */
u32 e_phoff; /* Program header offset */
u32 e_shoff; /* Section header offset */
u32 e_flags; /* Processor specific flags */
u16 e_ehsize; /* ELF header size */
u16 e_phentsize; /* Program header entry size */
u16 e_phnum; /* Number of program headers */
u16 e_shentsize; /* Section header entry size */
u16 e_shnum; /* Number of section headers */
u16 e_shstrndx; /* Shtable index for strings */
} __attribute__((__packed__));
#endif /* __ELF_H__ */

View File

@@ -0,0 +1,60 @@
/*
* Definitions for ELF Sections
* Based on Portable Formats Specification v1.1
*
* Copyright (C) 2008 Bahadir Balban
*/
#ifndef __ELFSECT_H__
#define __ELFSECT_H__
#include <l4/types.h>
/* Special section indices */
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xFF00
#define SHN_LOPROC 0xFF00
#define SHN_HIPROC 0xFF1F
#define SHN_ABS 0xFFF1
#define SHN_COMMON 0xFFF2
#define SHN_HIRESERVE 0xFFFF
struct elf_section_header {
u32 sh_name; /* Index to section header str table for name */
u32 sh_type; /* Categorises section's semantics */
u32 sh_flags; /* Flags that define various attributes */
u32 sh_addr; /* Virtual address for section */
u32 sh_offset; /* Offset to contents from file beginning */
u32 sh_size; /* Size of section (note SHT_NOBITS) */
u32 sh_link;
u32 sh_info; /* Extra section info */
u32 sh_addralign; /* Section alignment in power of 2 */
u32 sh_entsize; /* Size of each entry if fixed */
} __attribute__((__packed__));
/* Section type codes */
#define SHT_NULL 0 /* Inactive */
#define SHT_PROGBITS 1 /* Program contents */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking info */
#define SHT_NOTE 7 /* Optional, additional info */
#define SHT_NOBITS 8 /* Does not occupy file space */
#define SHT_REL 9 /* Relocation entries */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Symbols for dynamic linking */
#define SHT_LOPROC 0x70000000 /* Reserved for processors */
#define SHT_HIPROC 0x7FFFFFFF /* Reserved for processors */
#define SHT_LOUSER 0x80000000 /* Reserved for user progs */
#define SHT_HIUSER 0xFFFFFFFF /* Reserved for user progs */
/* Section attribute flags */
#define SHF_WRITE (1 << 0) /* Writeable */
#define SHF_ALLOC (1 << 1) /* Occupies actual memory */
#define SHF_EXECINSTR (1 << 2) /* Executable */
#define SHF_MASCPROC 0xF0000000 /* Reserved for processors */
#endif /* __ELFSECT_H__ */

View File

@@ -0,0 +1,59 @@
/*
* Definitions for ELF Symbol tables, symbols
* Based on Portable Formats Specification v1.1
*
* Copyright (C) 2008 Bahadir Balban
*/
#ifndef __ELFSYM_H__
#define __ELFSYM_H__
#include <l4/types.h>
struct elf_symbol_entry {
u32 st_name; /* Index into string table */
u32 st_value; /* Symbol value; address, aboslute etc. */
u32 st_size; /* Number of bytes contained in object */
u8 st_info; /* Type and binding attributes */
u8 st_other; /* Unused, 0 */
u16 st_shndx; /* Section header index associated with entry */
} __attribute__((__packed__));
/* To manipulate binding and type attributes on st_info field */
#define ELF32_ST_BIND(i) ((i) >> 4)
#define ELF32_ST_TYPE(i) ((i) & 0xF)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xF))
/* Symbol binding codes */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_LOPROC 13
#define STB_HIPROC 15
/* Symbol types */
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Relocation structures */
struct elf_rel {
u32 r_offset;
u32 r_info;
} __attribute__((__packed__));
struct elf_rela {
u32 r_offset;
u32 r_info;
s32 r_addend;
} __attribute__((__packed__));
/* Macros to manipulate r_info field */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((u8)(i))
#define ELF32_R_INFO(s,t) (((s) << 8) + (u8)(t))
#endif /* __ELFSYM_H__ */

View File

@@ -31,6 +31,7 @@ int sys_shmdt(struct tcb *requester, const void *shmaddr);
int sys_shmget(key_t key, int size, int shmflg);
int sys_execve(struct tcb *sender, char *pathname, char *argv[], char *envp[]);
int sys_fork(struct tcb *parent);
int sys_clone(struct tcb *parent, void *child_stack, unsigned int clone_flags);
void sys_exit(struct tcb *task, int status);

View File

@@ -17,6 +17,9 @@
#define __TASKNAME__ __PAGERNAME__
#define ARGS_MAX DEFAULT_ENV_SIZE
#define PATH_MAX PAGE_SIZE
#define TASK_FILES_MAX 32
/* POSIX minimum is 4Kb */

View File

@@ -135,6 +135,14 @@ void handle_requests(void)
sys_exit(sender, (int)mr[0]);
return;
}
case L4_IPC_TAG_EXECVE: {
ret = sys_execve(sender, (char *)mr[0],
(char **)mr[1], (char **)mr[2]);
if (ret < 0)
break; /* We reply for errors */
else
return; /* else we're done */
}
case L4_IPC_TAG_BRK: {
// ret = sys_brk(sender, (void *)mr[0]);
// break;

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)

View File

@@ -10,5 +10,6 @@ int dirtest(void);
int fileio(void);
int fileio2(void);
int clonetest(void);
void exectest(void);
#endif /* __TEST0_TESTS_H__ */

View File

@@ -33,11 +33,12 @@ void main(void)
dirtest();
exectest();
/* Check mmap/munmap */
mmaptest();
printf("Forking...\n");
if ((pid = fork()) < 0)
printf("Error forking...\n");

View File

@@ -47,3 +47,7 @@ int clonetest(void)
return 0;
}

View File

@@ -0,0 +1,14 @@
/*
* Execve test.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <tests.h>
void exectest(void)
{
execve("/usr/home/bahadir/executable", 0, 0);
}