mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Initial changes for execve() support
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
66
tasks/libposix/execve.c
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
61
tasks/mm0/include/lib/elf.h
Normal file
61
tasks/mm0/include/lib/elf.h
Normal 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__ */
|
||||
60
tasks/mm0/include/lib/elfsect.h
Normal file
60
tasks/mm0/include/lib/elfsect.h
Normal 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__ */
|
||||
59
tasks/mm0/include/lib/elfsym.h
Normal file
59
tasks/mm0/include/lib/elfsym.h
Normal 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__ */
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
213
tasks/mm0/src/execve.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -10,5 +10,6 @@ int dirtest(void);
|
||||
int fileio(void);
|
||||
int fileio2(void);
|
||||
int clonetest(void);
|
||||
void exectest(void);
|
||||
|
||||
#endif /* __TEST0_TESTS_H__ */
|
||||
|
||||
@@ -33,11 +33,12 @@ void main(void)
|
||||
|
||||
dirtest();
|
||||
|
||||
exectest();
|
||||
|
||||
/* Check mmap/munmap */
|
||||
mmaptest();
|
||||
|
||||
printf("Forking...\n");
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
printf("Error forking...\n");
|
||||
|
||||
|
||||
@@ -47,3 +47,7 @@ int clonetest(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
14
tasks/test0/src/exectest.c
Normal file
14
tasks/test0/src/exectest.c
Normal 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user