mirror of
https://github.com/drasko/codezero.git
synced 2026-10-17 00:07:27 +02:00
Merged fs0 to mm0 for simpler progress on posix api.
mm0 and all other posix dependents are building ok.
This commit is contained in:
+5
-12
@@ -70,19 +70,13 @@ mm0 = SConscript('mm0/SConscript', \
|
|||||||
exports = { 'config' : config, 'env' : mm0_env, 'contid' : contid }, duplicate = 0, \
|
exports = { 'config' : config, 'env' : mm0_env, 'contid' : contid }, duplicate = 0, \
|
||||||
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/mm0'))
|
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/mm0'))
|
||||||
|
|
||||||
fs0_env = env.Clone()
|
|
||||||
fs0_env.Append(CPPPATH = LIBPOSIX_INCLUDE_SERVER)
|
|
||||||
fs0 = SConscript('fs0/SConscript', \
|
|
||||||
exports = { 'config' : config, 'env' : fs0_env, 'contid' : contid, 'previmage' : mm0 }, duplicate = 0, \
|
|
||||||
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/fs0'))
|
|
||||||
|
|
||||||
test0_env = env.Clone()
|
test0_env = env.Clone()
|
||||||
test0_env.Replace(CPPPATH = ['include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE])
|
test0_env.Replace(CPPPATH = ['include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE])
|
||||||
test0 = SConscript('test0/SConscript', \
|
test0 = SConscript('test0/SConscript', \
|
||||||
exports = { 'config' : config, 'environment' : test0_env, 'contid' : contid, 'previmage' : fs0 }, duplicate = 0, \
|
exports = { 'config' : config, 'environment' : test0_env, 'contid' : contid, 'previmage' : mm0 }, duplicate = 0, \
|
||||||
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/test0'))
|
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/test0'))
|
||||||
|
|
||||||
images = [mm0, fs0, test0]
|
images = [mm0, test0]
|
||||||
bootdesc_env = env.Clone()
|
bootdesc_env = env.Clone()
|
||||||
bootdesc_env['bootdesc_dir'] = 'bootdesc'
|
bootdesc_env['bootdesc_dir'] = 'bootdesc'
|
||||||
|
|
||||||
@@ -91,14 +85,13 @@ bootdesc = SConscript('bootdesc/SConscript', \
|
|||||||
'contid' : contid, 'images' : images }, duplicate = 0, \
|
'contid' : contid, 'images' : images }, duplicate = 0, \
|
||||||
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/bootdesc'))
|
variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/bootdesc'))
|
||||||
|
|
||||||
Depends(fs0, libposix)
|
Depends(mm0, libposix)
|
||||||
Depends(test0, libposix)
|
Depends(test0, libposix)
|
||||||
Depends(bootdesc, [fs0, test0, mm0])
|
Depends(bootdesc, [test0, mm0])
|
||||||
|
|
||||||
Alias('libposix', libposix)
|
Alias('libposix', libposix)
|
||||||
Alias('mm0', mm0)
|
Alias('mm0', mm0)
|
||||||
Alias('fs0', fs0)
|
|
||||||
Alias('test0', test0)
|
Alias('test0', test0)
|
||||||
Alias('bootdesc', bootdesc)
|
Alias('bootdesc', bootdesc)
|
||||||
|
|
||||||
Default([mm0, fs0, libposix, test0, bootdesc])
|
Default([mm0, libposix, test0, bootdesc])
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
|
|
||||||
Import('config', 'env', 'previmage', 'contid')
|
|
||||||
|
|
||||||
import os, sys
|
|
||||||
|
|
||||||
arch = config.arch
|
|
||||||
|
|
||||||
sys.path.append('../../../')
|
|
||||||
|
|
||||||
from config.lib import *
|
|
||||||
from tools.pyelf.lmanext import *
|
|
||||||
|
|
||||||
src = [Glob('*.c') + Glob('src/*.c') + Glob('src/arch/arm/*.c') + Glob('src/memfs/*.c') + Glob('src/lib/*.c')]
|
|
||||||
|
|
||||||
def generate_lma_lds(target, source, env):
|
|
||||||
with open(source[1].path, 'r') as lds_in:
|
|
||||||
with open(target[0].path, 'w+') as lds_out:
|
|
||||||
linker_script = lds_in.read()
|
|
||||||
lds_out.write(linker_script % next_available_lma(source[0].path))
|
|
||||||
|
|
||||||
lma_lds = Command('include/linker.lds', [previmage, 'include/linker.lds.in'], generate_lma_lds)
|
|
||||||
|
|
||||||
e = env.Clone()
|
|
||||||
e.Append(LIBS = 'posix')
|
|
||||||
e.Append(LINKFLAGS = ['-T' + lma_lds[0].path, '-u_start'])
|
|
||||||
|
|
||||||
objs = e.Object(src)
|
|
||||||
fs0 = e.Program('fs0.elf', objs)
|
|
||||||
Depends(fs0, lma_lds)
|
|
||||||
Return('fs0')
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#
|
|
||||||
# User space application build script
|
|
||||||
#
|
|
||||||
# Copyright (C) 2007 Bahadir Balban
|
|
||||||
#
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
from os.path import join
|
|
||||||
from glob import glob
|
|
||||||
|
|
||||||
task_name = "fs0"
|
|
||||||
|
|
||||||
# The root directory of the repository where this file resides:
|
|
||||||
project_root = "../.."
|
|
||||||
tools_root = join(project_root, "tools")
|
|
||||||
prev_image = join(project_root, "tasks/mm0/mm0.axf")
|
|
||||||
libs_path = join(project_root, "libs")
|
|
||||||
ld_script = "include/linker.lds"
|
|
||||||
physical_base_ld_script = "include/physical_base.lds"
|
|
||||||
|
|
||||||
# libc paths:
|
|
||||||
libc_variant = "userspace"
|
|
||||||
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
|
|
||||||
libc_incpath = join(libc_libpath, "include")
|
|
||||||
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
|
|
||||||
libc_name = "c-%s" % libc_variant
|
|
||||||
|
|
||||||
#libmem paths:
|
|
||||||
libmem_path = "../libmem"
|
|
||||||
libmem_incpath = "../libmem"
|
|
||||||
|
|
||||||
# libl4 paths:
|
|
||||||
libl4_path = "../libl4"
|
|
||||||
libl4_incpath1 = join(libl4_path, "include")
|
|
||||||
|
|
||||||
# libposix paths:
|
|
||||||
libposix_path = "../libposix"
|
|
||||||
libposix_incpath = join(libposix_path, "include")
|
|
||||||
|
|
||||||
# kernel paths:
|
|
||||||
kernel_incpath = join(project_root, "include")
|
|
||||||
|
|
||||||
# If crt0 is in its library path, it becomes hard to link with it.
|
|
||||||
# For instance the linker script must use an absolute path for it.
|
|
||||||
def copy_crt0(source, target, env):
|
|
||||||
os.system("cp " + str(source[0]) + " " + str(target[0]))
|
|
||||||
|
|
||||||
def get_physical_base(source, target, env):
|
|
||||||
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
|
|
||||||
prev_image + " >> " + physical_base_ld_script))
|
|
||||||
|
|
||||||
# The kernel build environment:
|
|
||||||
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
|
|
||||||
# We don't use -nostdinc because sometimes we need standard headers,
|
|
||||||
# such as stdarg.h e.g. for variable args, as in printk().
|
|
||||||
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
|
|
||||||
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path,\
|
|
||||||
"-L" + libmem_path, "-L" + libposix_path],
|
|
||||||
ASFLAGS = ['-D__ASSEMBLY__'],
|
|
||||||
PROGSUFFIX = '.axf', # The suffix to use for final executable
|
|
||||||
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
|
|
||||||
LIBS = [libc_name, 'gcc', 'libmc', 'libl4', 'gcc', libc_name, "posix"],
|
|
||||||
CPPFLAGS = "-D__USERSPACE__",
|
|
||||||
CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath, \
|
|
||||||
libposix_incpath, libmem_incpath])
|
|
||||||
|
|
||||||
src = [glob("src/*.c"), glob("*.c"), glob("src/arch/arm/*.c"), glob("src/memfs/*.c"), glob("src/lib/*.c")]
|
|
||||||
objs = env.Object(src)
|
|
||||||
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
|
|
||||||
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
|
|
||||||
|
|
||||||
task = env.Program(task_name, objs + [crt0_copied])
|
|
||||||
env.Alias(task_name, task)
|
|
||||||
env.Depends(task, physical_base)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Container entry point for this task
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
|
||||||
*/
|
|
||||||
#include <posix/posix_init.h>
|
|
||||||
#include <l4lib/init.h>
|
|
||||||
#include <l4lib/utcb.h>
|
|
||||||
|
|
||||||
void main(void);
|
|
||||||
|
|
||||||
void __container_init(void)
|
|
||||||
{
|
|
||||||
/* Generic L4 thread initialisation */
|
|
||||||
__l4_init();
|
|
||||||
|
|
||||||
/* FS0 posix-service initialisation */
|
|
||||||
posix_service_init();
|
|
||||||
|
|
||||||
/* Entry to main */
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#ifndef __FS0_MM_H__
|
|
||||||
#define __FS0_MM_H__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __FS0_MM_H__ */
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#ifndef __GLOBALS_H__
|
|
||||||
#define __GLOBALS_H__
|
|
||||||
|
|
||||||
struct global_list {
|
|
||||||
int total;
|
|
||||||
struct link list;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct global_list global_vm_files;
|
|
||||||
extern struct global_list global_vm_objects;
|
|
||||||
extern struct global_list global_tasks;
|
|
||||||
|
|
||||||
#endif /* __GLOBALS_H__ */
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef __INIT_H__
|
|
||||||
#define __INIT_H__
|
|
||||||
|
|
||||||
/* FS0 initialisation */
|
|
||||||
int initialise(void);
|
|
||||||
|
|
||||||
#endif /* __INIT_H__ */
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#ifndef __LIB_BIT_H__
|
|
||||||
#define __LIB_BIT_H__
|
|
||||||
|
|
||||||
#include <l4lib/types.h>
|
|
||||||
|
|
||||||
unsigned int __clz(unsigned int bitvector);
|
|
||||||
int find_and_set_first_free_bit(u32 *word, unsigned int lastbit);
|
|
||||||
int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
|
|
||||||
int nbits);
|
|
||||||
int check_and_clear_bit(u32 *word, int bit);
|
|
||||||
int check_and_clear_contig_bits(u32 *word, int first, int nbits);
|
|
||||||
|
|
||||||
int check_and_set_bit(u32 *word, int bit);
|
|
||||||
|
|
||||||
/* Set */
|
|
||||||
static inline void setbit(unsigned int *w, unsigned int flags)
|
|
||||||
{
|
|
||||||
*w |= flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Clear */
|
|
||||||
static inline void clrbit(unsigned int *w, unsigned int flags)
|
|
||||||
{
|
|
||||||
*w &= ~flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test */
|
|
||||||
static inline int tstbit(unsigned int *w, unsigned int flags)
|
|
||||||
{
|
|
||||||
return *w & flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test and clear */
|
|
||||||
static inline int tstclr(unsigned int *w, unsigned int flags)
|
|
||||||
{
|
|
||||||
int res = tstbit(w, flags);
|
|
||||||
|
|
||||||
clrbit(w, flags);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __LIB_BIT_H__ */
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef __MM0_IDPOOL_H__
|
|
||||||
#define __MM0_IDPOOL_H__
|
|
||||||
|
|
||||||
#include <lib/bit.h>
|
|
||||||
#include <l4/macros.h>
|
|
||||||
#include INC_GLUE(memory.h)
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
struct id_pool {
|
|
||||||
int nwords;
|
|
||||||
u32 bitmap[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy one id pool to another by calculating its size */
|
|
||||||
static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int totalbits)
|
|
||||||
{
|
|
||||||
int nwords = BITWISE_GETWORD(totalbits);
|
|
||||||
|
|
||||||
memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct id_pool *id_pool_new_init(int mapsize);
|
|
||||||
int id_new(struct id_pool *pool);
|
|
||||||
int id_del(struct id_pool *pool, int id);
|
|
||||||
int id_get(struct id_pool *pool, int id);
|
|
||||||
int ids_new_contiguous(struct id_pool *pool, int numids);
|
|
||||||
int ids_del_contiguous(struct id_pool *pool, int first, int numids);
|
|
||||||
|
|
||||||
#endif /* __MM0_IDPOOL_H__ */
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef __PRIVATE_MALLOC_H__
|
|
||||||
#define __PRIVATE_MALLOC_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void *kmalloc(size_t size);
|
|
||||||
void kfree(void *blk);
|
|
||||||
|
|
||||||
static inline void *kzalloc(size_t size)
|
|
||||||
{
|
|
||||||
void *buf = kmalloc(size);
|
|
||||||
|
|
||||||
memset(buf, 0, size);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*__PRIVATE_MALLOC_H__ */
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* Fake spinlock for future multi-threaded mm0
|
|
||||||
*/
|
|
||||||
#ifndef __MM0_SPINLOCK_H__
|
|
||||||
#define __MM0_SPINLOCK_H__
|
|
||||||
|
|
||||||
struct spinlock {
|
|
||||||
int lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void spin_lock_init(struct spinlock *s) { }
|
|
||||||
static inline void spin_lock(struct spinlock *s) { }
|
|
||||||
static inline void spin_unlock(struct spinlock *s) { }
|
|
||||||
|
|
||||||
#endif /* __MM0_SPINLOCK_H__ */
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Simple linker script for userspace or svc tasks.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* USER_AREA_START, see memlayout.h */
|
|
||||||
virtual_base = 0x10000000;
|
|
||||||
physical_base = %s;
|
|
||||||
__stack = (0x20000000 - 0x1000 - 8); /* First page before env/args page */
|
|
||||||
/* INCLUDE "include/physical_base.lds" */
|
|
||||||
|
|
||||||
/* physical_base = 0x228000; */
|
|
||||||
offset = virtual_base - physical_base;
|
|
||||||
|
|
||||||
ENTRY(_start)
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = virtual_base;
|
|
||||||
_start_text = .;
|
|
||||||
.text : AT (ADDR(.text) - offset) { *(.text.head) *(.text) }
|
|
||||||
/* rodata is needed else your strings will link at physical! */
|
|
||||||
.rodata : AT (ADDR(.rodata) - offset) { *(.rodata) }
|
|
||||||
.rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) }
|
|
||||||
.data : AT (ADDR(.data) - offset)
|
|
||||||
{
|
|
||||||
. = ALIGN(4K); /* Align UTCB to page boundary */
|
|
||||||
_start_utcb = .;
|
|
||||||
*(.utcb)
|
|
||||||
_end_utcb = .;
|
|
||||||
. = ALIGN(4K);
|
|
||||||
_start_bdev = .;
|
|
||||||
*(.data.memfs)
|
|
||||||
_end_bdev = .;
|
|
||||||
*(.data)
|
|
||||||
}
|
|
||||||
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
|
|
||||||
|
|
||||||
_end = .;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* System call function signatures.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007, 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#ifndef __FS0_SYSCALLS_H__
|
|
||||||
#define __FS0_SYSCALLS_H__
|
|
||||||
|
|
||||||
#include <task.h>
|
|
||||||
|
|
||||||
/* Posix calls */
|
|
||||||
int sys_open(struct tcb *sender, const char *pathname, int flags, u32 mode);
|
|
||||||
int sys_readdir(struct tcb *sender, int fd, void *buf, int count);
|
|
||||||
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);
|
|
||||||
|
|
||||||
int pager_sys_write(struct tcb *sender, unsigned long vnum, unsigned long f_offset,
|
|
||||||
unsigned long npages, void *pagebuf);
|
|
||||||
|
|
||||||
int pager_sys_close(struct tcb *sender, l4id_t closer, int fd);
|
|
||||||
int pager_update_stats(struct tcb *sender, unsigned long vnum,
|
|
||||||
unsigned long newsize);
|
|
||||||
|
|
||||||
int pager_notify_fork(struct tcb *sender, l4id_t parentid,
|
|
||||||
l4id_t childid, unsigned long utcb_address,
|
|
||||||
unsigned int flags);
|
|
||||||
|
|
||||||
int pager_notify_exit(struct tcb *sender, l4id_t tid);
|
|
||||||
#endif /* __FS0_SYSCALLS_H__ */
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#ifndef __FS0_TASK_H__
|
|
||||||
#define __FS0_TASK_H__
|
|
||||||
|
|
||||||
#include <lib/idpool.h>
|
|
||||||
#include <l4/lib/list.h>
|
|
||||||
#include <l4/api/kip.h>
|
|
||||||
|
|
||||||
#define __TASKNAME__ __VFSNAME__
|
|
||||||
|
|
||||||
#define TCB_NO_SHARING 0
|
|
||||||
#define TCB_SHARED_VM (1 << 0)
|
|
||||||
#define TCB_SHARED_FILES (1 << 1)
|
|
||||||
#define TCB_SHARED_FS (1 << 2)
|
|
||||||
|
|
||||||
#define TASK_FILES_MAX 32
|
|
||||||
|
|
||||||
struct task_fd_head {
|
|
||||||
int fd[TASK_FILES_MAX];
|
|
||||||
struct id_pool *fdpool;
|
|
||||||
int tcb_refs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct task_fs_data {
|
|
||||||
struct vnode *curdir;
|
|
||||||
struct vnode *rootdir;
|
|
||||||
int tcb_refs;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Thread control block, fs0 portion */
|
|
||||||
struct tcb {
|
|
||||||
l4id_t tid;
|
|
||||||
struct link list;
|
|
||||||
unsigned long shpage_address;
|
|
||||||
struct task_fd_head *files;
|
|
||||||
struct task_fs_data *fs_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structures used when receiving new task info from pager */
|
|
||||||
struct task_data {
|
|
||||||
unsigned long tid;
|
|
||||||
unsigned long shpage_address;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct task_data_head {
|
|
||||||
unsigned long total;
|
|
||||||
struct task_data tdata[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tcb *find_task(int tid);
|
|
||||||
int init_task_data(void);
|
|
||||||
|
|
||||||
#endif /* __FS0_TASK_H__ */
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* FS0. Filesystem implementation
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <l4lib/arch/syscalls.h>
|
|
||||||
#include <l4lib/arch/syslib.h>
|
|
||||||
#include <l4lib/kip.h>
|
|
||||||
#include <l4lib/utcb.h>
|
|
||||||
#include <l4lib/ipcdefs.h>
|
|
||||||
#include <fs.h>
|
|
||||||
#include <init.h>
|
|
||||||
#include <syscalls.h>
|
|
||||||
#include <task.h>
|
|
||||||
#include <posix/sys/time.h>
|
|
||||||
#include <l4/api/errno.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO:
|
|
||||||
* - Have a dentry cache searchable by name
|
|
||||||
* - Have a vnode cache searchable by vnum (and name?)
|
|
||||||
* - fs-specific readdir would read contents by page range, and add vnodes/dentries
|
|
||||||
* to their caches, while populating the directory vnode being read.
|
|
||||||
* - Have 2 vfs_lookup() flavors, one that searches a path, one that searches a vnum.
|
|
||||||
* - dirbuf is either allocated by low-level readdir, or else by a higher level, i.e.
|
|
||||||
* either high-level vfs code, or the mm0 page cache.
|
|
||||||
* - readdir provides a posix-compliant dirent structure list in dirbuf.
|
|
||||||
* - memfs dentries should be identical to posix struct dirents.
|
|
||||||
*
|
|
||||||
* ALL DONE!!! But untested.
|
|
||||||
*
|
|
||||||
* - Add mkdir
|
|
||||||
* - Add create
|
|
||||||
* - Add read/write -> This will need page cache and mm0 involvement.
|
|
||||||
*
|
|
||||||
* Done those, too. but untested.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Synchronise with pager via a `wait' tagged ipc with destination as pager */
|
|
||||||
void wait_pager(l4id_t partner)
|
|
||||||
{
|
|
||||||
l4_send(partner, L4_IPC_TAG_SYNC);
|
|
||||||
// printf("%s: Pager synced with us.\n", __TASKNAME__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_fs_requests(void)
|
|
||||||
{
|
|
||||||
u32 mr[MR_UNUSED_TOTAL];
|
|
||||||
l4id_t senderid;
|
|
||||||
struct tcb *sender;
|
|
||||||
int ret;
|
|
||||||
u32 tag;
|
|
||||||
|
|
||||||
if ((ret = l4_receive(L4_ANYTHREAD)) < 0) {
|
|
||||||
printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__,
|
|
||||||
__FUNCTION__, ret);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read conventional ipc data */
|
|
||||||
tag = l4_get_tag();
|
|
||||||
senderid = l4_get_sender();
|
|
||||||
|
|
||||||
if (!(sender = find_task(senderid))) {
|
|
||||||
l4_ipc_return(-ESRCH);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read mrs not used by syslib */
|
|
||||||
for (int i = 0; i < MR_UNUSED_TOTAL; i++)
|
|
||||||
mr[i] = read_mr(MR_UNUSED_START + i);
|
|
||||||
|
|
||||||
/* FIXME: Fix all these syscalls to read any buffer data from the caller task's utcb.
|
|
||||||
* Make sure to return -EINVAL if data is not valid. */
|
|
||||||
switch(tag) {
|
|
||||||
case L4_IPC_TAG_SYNC:
|
|
||||||
printf("%s: Synced with waiting thread.\n", __TASKNAME__);
|
|
||||||
return; /* No origy for this tag */
|
|
||||||
case L4_IPC_TAG_OPEN:
|
|
||||||
ret = sys_open(sender, (void *)mr[0], (int)mr[1], (unsigned int)mr[2]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_MKDIR:
|
|
||||||
ret = sys_mkdir(sender, (const char *)mr[0], (unsigned int)mr[1]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_CHDIR:
|
|
||||||
ret = sys_chdir(sender, (const char *)mr[0]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_READDIR:
|
|
||||||
ret = sys_readdir(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_PAGER_READ:
|
|
||||||
ret = pager_sys_read(sender, (unsigned long)mr[0], (unsigned long)mr[1],
|
|
||||||
(unsigned long)mr[2], (void *)mr[3]);
|
|
||||||
break;
|
|
||||||
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]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_PAGER_CLOSE:
|
|
||||||
ret = pager_sys_close(sender, (l4id_t)mr[0], (int)mr[1]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_PAGER_UPDATE_STATS:
|
|
||||||
ret = pager_update_stats(sender, (unsigned long)mr[0],
|
|
||||||
(unsigned long)mr[1]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_NOTIFY_FORK:
|
|
||||||
ret = pager_notify_fork(sender, (l4id_t)mr[0], (l4id_t)mr[1],
|
|
||||||
(unsigned long)mr[2], (unsigned int)mr[3]);
|
|
||||||
break;
|
|
||||||
case L4_IPC_TAG_NOTIFY_EXIT:
|
|
||||||
ret = pager_notify_exit(sender, (l4id_t)mr[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf("%s: Unrecognised ipc tag (%d) "
|
|
||||||
"received from tid: %d. Ignoring.\n", __TASKNAME__,
|
|
||||||
mr[MR_TAG], senderid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reply */
|
|
||||||
if ((ret = l4_ipc_return(ret)) < 0) {
|
|
||||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
printf("\n%s: Started with thread id %d\n", __TASKNAME__, self_tid());
|
|
||||||
|
|
||||||
initialise();
|
|
||||||
|
|
||||||
wait_pager(PAGER_TID);
|
|
||||||
|
|
||||||
printf("%s: VFS service initialized. Listening requests.\n", __TASKNAME__);
|
|
||||||
while (1) {
|
|
||||||
handle_fs_requests();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* A pseudo-filesystem for reading the in-memory
|
|
||||||
* server tasks loaded from the initial elf executable.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007, 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <fs.h>
|
|
||||||
#include <l4/lib/list.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
struct dentry *bootfs_dentry_lookup(struct dentry *d, char *dname)
|
|
||||||
{
|
|
||||||
struct dentry *this;
|
|
||||||
|
|
||||||
list_foreach_struct(this, child, &d->children) {
|
|
||||||
if (this->compare(this, dname))
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dentry *path_lookup(struct superblock *sb, char *pathstr)
|
|
||||||
{
|
|
||||||
char *dname;
|
|
||||||
char *splitpath;
|
|
||||||
struct dentry *this, *next;
|
|
||||||
|
|
||||||
/* First dentry is root */
|
|
||||||
this = sb->root;
|
|
||||||
|
|
||||||
/* Get next path component from path string */
|
|
||||||
dname = path_next_dentry_name(pathstr);
|
|
||||||
|
|
||||||
if (!this->compare(dname))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while(!(dname = path_next_dentry_name(pathstr))) {
|
|
||||||
if ((d = this->lookup(this, dname)))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This creates a pseudo-filesystem tree from the loaded
|
|
||||||
* server elf images whose information is available from
|
|
||||||
* initdata.
|
|
||||||
*/
|
|
||||||
void bootfs_populate(struct initdata *initdata, struct superblock *sb)
|
|
||||||
{
|
|
||||||
struct bootdesc *bd = initdata->bootdesc;
|
|
||||||
struct svc_image *img;
|
|
||||||
struct dentry *d;
|
|
||||||
struct vnode *v;
|
|
||||||
struct file *f;
|
|
||||||
|
|
||||||
for (int i = 0; i < bd->total_images; i++) {
|
|
||||||
img = &bd->images[i];
|
|
||||||
|
|
||||||
d = malloc(sizeof(struct dentry));
|
|
||||||
v = malloc(sizeof(struct vnode));
|
|
||||||
f = malloc(sizeof(struct file));
|
|
||||||
|
|
||||||
/* Initialise dentry for image */
|
|
||||||
d->refcnt = 0;
|
|
||||||
d->vnode = v;
|
|
||||||
d->parent = sb->root;
|
|
||||||
strncpy(d->name, img->name, VFS_DENTRY_NAME_MAX);
|
|
||||||
link_init(&d->child);
|
|
||||||
link_init(&d->children);
|
|
||||||
list_insert(&d->child, &sb->root->children);
|
|
||||||
|
|
||||||
/* Initialise vnode for image */
|
|
||||||
v->refcnt = 0;
|
|
||||||
v->id = img->phys_start;
|
|
||||||
v->size = img->phys_end - img->phys_start;
|
|
||||||
link_init(&v->dirents);
|
|
||||||
list_insert(&d->v_ref, &v->dirents);
|
|
||||||
|
|
||||||
/* Initialise file struct for image */
|
|
||||||
f->refcnt = 0;
|
|
||||||
f->dentry = d;
|
|
||||||
|
|
||||||
img_d++;
|
|
||||||
img_vn++;
|
|
||||||
img_f++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootfs_init_root(struct dentry *r)
|
|
||||||
{
|
|
||||||
struct vnode *v = r->vnode;
|
|
||||||
|
|
||||||
/* Initialise dentry for rootdir */
|
|
||||||
r->refcnt = 0;
|
|
||||||
strcpy(r->name, "");
|
|
||||||
link_init(&r->child);
|
|
||||||
link_init(&r->children);
|
|
||||||
link_init(&r->vref);
|
|
||||||
r->parent = r;
|
|
||||||
|
|
||||||
/* Initialise vnode for rootdir */
|
|
||||||
v->id = 0;
|
|
||||||
v->refcnt = 0;
|
|
||||||
link_init(&v->dirents);
|
|
||||||
link_init(&v->state_list);
|
|
||||||
list_insert(&r->vref, &v->dirents);
|
|
||||||
v->size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct superblock *bootfs_init_sb(struct superblock *sb)
|
|
||||||
{
|
|
||||||
sb->root = malloc(sizeof(struct dentry));
|
|
||||||
sb->root->vnode = malloc(sizeof(struct vnode));
|
|
||||||
|
|
||||||
bootfs_init_root(&sb->root);
|
|
||||||
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct superblock bootfs_sb = {
|
|
||||||
.fs = bootfs_type,
|
|
||||||
.ops = {
|
|
||||||
.read_sb = bootfs_read_sb,
|
|
||||||
.write_sb = bootfs_write_sb,
|
|
||||||
.read_vnode = bootfs_read_vnode,
|
|
||||||
.write_vnode = bootfs_write_vnode,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
struct superblock *bootfs_get_sb(void)
|
|
||||||
{
|
|
||||||
bootfs_init_sb(&bootfs_sb);
|
|
||||||
return &bootfs_sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct file_system_type bootfs_type = {
|
|
||||||
.name = "bootfs",
|
|
||||||
.magic = 0,
|
|
||||||
.get_sb = bootfs_get_sb,
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_bootfs()
|
|
||||||
{
|
|
||||||
bootfs_init_sb(&bootfs_sb);
|
|
||||||
|
|
||||||
bootfs_populate(&bootfs_sb);
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* A basic unix-like read/writeable filesystem for Codezero.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007, 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <init.h>
|
|
||||||
#include <fs.h>
|
|
||||||
|
|
||||||
void sfs_read_sb(struct superblock *sb)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void simplefs_alloc_vnode(struct vnode *)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct file_system_type sfs_type = {
|
|
||||||
.name = "c0fs",
|
|
||||||
.magic = 1,
|
|
||||||
.flags = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Registers sfs as an available filesystem type */
|
|
||||||
void sfs_register_fstype(struct link *fslist)
|
|
||||||
{
|
|
||||||
list_insert(&sfs_type.list, fslist);
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* Bit manipulation functions.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <lib/bit.h>
|
|
||||||
#include <l4/macros.h>
|
|
||||||
#include <l4/config.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include INC_GLUE(memory.h)
|
|
||||||
|
|
||||||
/* Emulation of ARM's CLZ (count leading zeroes) instruction */
|
|
||||||
unsigned int __clz(unsigned int bitvector)
|
|
||||||
{
|
|
||||||
unsigned int x = 0;
|
|
||||||
while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) {
|
|
||||||
bitvector <<= 1;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_and_set_first_free_bit(u32 *word, unsigned int limit)
|
|
||||||
{
|
|
||||||
int success = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < limit; i++) {
|
|
||||||
/* Find first unset bit */
|
|
||||||
if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
|
|
||||||
/* Set it */
|
|
||||||
word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
|
|
||||||
success = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Return bit just set */
|
|
||||||
if (success)
|
|
||||||
return i;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
|
|
||||||
int nbits)
|
|
||||||
{
|
|
||||||
int i = 0, first = 0, last = 0, found = 0;
|
|
||||||
|
|
||||||
/* Can't allocate more than the limit */
|
|
||||||
if (nbits > limit)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* This is a state machine that checks n contiguous free bits. */
|
|
||||||
while (i + nbits < limit) {
|
|
||||||
first = i;
|
|
||||||
last = i;
|
|
||||||
while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) {
|
|
||||||
last++;
|
|
||||||
i++;
|
|
||||||
if (last == first + nbits) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If found, set the bits */
|
|
||||||
if (found) {
|
|
||||||
for (int x = first; x < first + nbits; x++)
|
|
||||||
word[BITWISE_GETWORD(x)] |= BITWISE_GETBIT(x);
|
|
||||||
return first;
|
|
||||||
} else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int check_and_clear_bit(u32 *word, int bit)
|
|
||||||
{
|
|
||||||
/* Check that bit was set */
|
|
||||||
if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
|
|
||||||
word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
printf("Trying to clear already clear bit\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int check_and_clear_contig_bits(u32 *word, int first, int nbits)
|
|
||||||
{
|
|
||||||
for (int i = first; i < first + nbits; i++)
|
|
||||||
if (check_and_clear_bit(word, i) < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int check_and_set_bit(u32 *word, int bit)
|
|
||||||
{
|
|
||||||
/* Check that bit was clear */
|
|
||||||
if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) {
|
|
||||||
word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
//printf("Trying to set already set bit\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Used for thread and space ids.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <lib/idpool.h>
|
|
||||||
// #include <kmalloc/kmalloc.h> --> This requires page allocation to grow/shrink.
|
|
||||||
#include <lib/malloc.h> // --> This is a local library that statically allocates its heap.
|
|
||||||
#include <l4/macros.h>
|
|
||||||
#include INC_GLUE(memory.h)
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <l4/api/errno.h>
|
|
||||||
|
|
||||||
struct id_pool *id_pool_new_init(int totalbits)
|
|
||||||
{
|
|
||||||
int nwords = BITWISE_GETWORD(totalbits);
|
|
||||||
struct id_pool *new = kzalloc((nwords * SZ_WORD)
|
|
||||||
+ sizeof(struct id_pool));
|
|
||||||
if (!new)
|
|
||||||
return PTR_ERR(-ENOMEM);
|
|
||||||
new->nwords = nwords;
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
int id_new(struct id_pool *pool)
|
|
||||||
{
|
|
||||||
int id = find_and_set_first_free_bit(pool->bitmap,
|
|
||||||
pool->nwords * WORD_BITS);
|
|
||||||
if (id < 0)
|
|
||||||
printf("%s: Warning! New id alloc failed\n", __FUNCTION__);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This finds n contiguous free ids, allocates and returns the first one */
|
|
||||||
int ids_new_contiguous(struct id_pool *pool, int numids)
|
|
||||||
{
|
|
||||||
int id = find_and_set_first_free_contig_bits(pool->bitmap,
|
|
||||||
pool->nwords *WORD_BITS,
|
|
||||||
numids);
|
|
||||||
if (id < 0)
|
|
||||||
printf("%s: Warning! New id alloc failed\n", __FUNCTION__);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This deletes a list of contiguous ids given the first one and number of ids */
|
|
||||||
int ids_del_contiguous(struct id_pool *pool, int first, int numids)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (pool->nwords * WORD_BITS < first + numids)
|
|
||||||
return -1;
|
|
||||||
if ((ret = check_and_clear_contig_bits(pool->bitmap, first, numids)))
|
|
||||||
printf("%s: Error: Invalid argument range.\n", __FUNCTION__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int id_del(struct id_pool *pool, int id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (pool->nwords * WORD_BITS < id)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if ((ret = check_and_clear_bit(pool->bitmap, id) < 0))
|
|
||||||
printf("%s: Error: Could not delete id.\n", __FUNCTION__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a specific id, if available */
|
|
||||||
int id_get(struct id_pool *pool, int id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = check_and_set_bit(pool->bitmap, id);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
else
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,417 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
Simple malloc
|
|
||||||
Chris Giese <geezer@execpc.com> http://www.execpc.com/~geezer
|
|
||||||
Release date: Oct 30, 2002
|
|
||||||
This code is public domain (no copyright).
|
|
||||||
You can do whatever you want with it.
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- First-fit
|
|
||||||
- free() coalesces adjacent free blocks
|
|
||||||
- Uses variable-sized heap, enlarged with kbrk()/sbrk() function
|
|
||||||
- Does not use mmap()
|
|
||||||
- Can be easily modified to use fixed-size heap
|
|
||||||
- Works with 16- or 32-bit compilers
|
|
||||||
|
|
||||||
Build this program with either of the two main() functions, then run it.
|
|
||||||
Messages that indicate a software error will contain three asterisks (***).
|
|
||||||
*****************************************************************************/
|
|
||||||
#include <string.h> /* memcpy(), memset() */
|
|
||||||
#include <stdio.h> /* printf() */
|
|
||||||
|
|
||||||
#define _32BIT 1
|
|
||||||
|
|
||||||
/* use small (32K) heap for 16-bit compilers,
|
|
||||||
large (500K) heap for 32-bit compilers */
|
|
||||||
#if defined(_32BIT)
|
|
||||||
#define HEAP_SIZE 500000uL
|
|
||||||
#else
|
|
||||||
#define HEAP_SIZE 32768u
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */
|
|
||||||
|
|
||||||
typedef struct _malloc /* Turbo C DJGPP */
|
|
||||||
{
|
|
||||||
size_t size; /* 2 bytes 4 bytes */
|
|
||||||
struct _malloc *next; /* 2 bytes 4 bytes */
|
|
||||||
unsigned magic : 15; /* 2 bytes total 4 bytes total */
|
|
||||||
unsigned used : 1;
|
|
||||||
} malloc_t; /* total 6 bytes 12 bytes */
|
|
||||||
|
|
||||||
static char *g_heap_bot, *g_kbrk, *g_heap_top;
|
|
||||||
/*****************************************************************************
|
|
||||||
*****************************************************************************/
|
|
||||||
void dump_heap(void)
|
|
||||||
{
|
|
||||||
unsigned blks_used = 0, blks_free = 0;
|
|
||||||
size_t bytes_used = 0, bytes_free = 0;
|
|
||||||
malloc_t *m;
|
|
||||||
int total;
|
|
||||||
|
|
||||||
printf("===============================================\n");
|
|
||||||
for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next)
|
|
||||||
{
|
|
||||||
printf("blk %5p: %6u bytes %s\n", m,
|
|
||||||
m->size, m->used ? "used" : "free");
|
|
||||||
if(m->used)
|
|
||||||
{
|
|
||||||
blks_used++;
|
|
||||||
bytes_used += m->size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
blks_free++;
|
|
||||||
bytes_free += m->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("blks: %6u used, %6u free, %6u total\n", blks_used,
|
|
||||||
blks_free, blks_used + blks_free);
|
|
||||||
printf("bytes: %6u used, %6u free, %6u total\n", bytes_used,
|
|
||||||
bytes_free, bytes_used + bytes_free);
|
|
||||||
printf("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n",
|
|
||||||
g_heap_bot, g_kbrk, g_heap_top);
|
|
||||||
total = (bytes_used + bytes_free) +
|
|
||||||
(blks_used + blks_free) * sizeof(malloc_t);
|
|
||||||
if(total != g_kbrk - g_heap_bot)
|
|
||||||
printf("*** some heap memory is not accounted for\n");
|
|
||||||
printf("===============================================\n");
|
|
||||||
}
|
|
||||||
/*****************************************************************************
|
|
||||||
POSIX sbrk() looks like this
|
|
||||||
void *sbrk(int incr);
|
|
||||||
Mine is a bit different so I can signal the calling function
|
|
||||||
if more memory than desired was allocated (e.g. in a system with paging)
|
|
||||||
If your kbrk()/sbrk() always allocates the amount of memory you ask for,
|
|
||||||
this code can be easily changed.
|
|
||||||
|
|
||||||
int brk( void *sbrk( void *kbrk(
|
|
||||||
function void *adr); int delta); int *delta);
|
|
||||||
---------------------- ------------ ------------ -------------
|
|
||||||
POSIX? yes yes NO
|
|
||||||
return value if error -1 -1 NULL
|
|
||||||
get break value . sbrk(0) int x=0; kbrk(&x);
|
|
||||||
set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y);
|
|
||||||
enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x);
|
|
||||||
shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x);
|
|
||||||
can you tell if you're
|
|
||||||
given more memory
|
|
||||||
than you wanted? no no yes
|
|
||||||
*****************************************************************************/
|
|
||||||
static void *kbrk(int *delta)
|
|
||||||
{
|
|
||||||
static char heap[HEAP_SIZE];
|
|
||||||
/**/
|
|
||||||
char *new_brk, *old_brk;
|
|
||||||
|
|
||||||
/* heap doesn't exist yet */
|
|
||||||
if(g_heap_bot == NULL)
|
|
||||||
{
|
|
||||||
g_heap_bot = g_kbrk = heap;
|
|
||||||
g_heap_top = g_heap_bot + HEAP_SIZE;
|
|
||||||
}
|
|
||||||
new_brk = g_kbrk + (*delta);
|
|
||||||
/* too low: return NULL */
|
|
||||||
if(new_brk < g_heap_bot)
|
|
||||||
return NULL;
|
|
||||||
/* too high: return NULL */
|
|
||||||
if(new_brk >= g_heap_top)
|
|
||||||
return NULL;
|
|
||||||
/* success: adjust brk value... */
|
|
||||||
old_brk = g_kbrk;
|
|
||||||
g_kbrk = new_brk;
|
|
||||||
/* ...return actual delta... (for this sbrk(), they are the same)
|
|
||||||
(*delta) = (*delta); */
|
|
||||||
/* ...return old brk value */
|
|
||||||
return old_brk;
|
|
||||||
}
|
|
||||||
/*****************************************************************************
|
|
||||||
kmalloc() and kfree() use g_heap_bot, but not g_kbrk nor g_heap_top
|
|
||||||
*****************************************************************************/
|
|
||||||
void *kmalloc(size_t size)
|
|
||||||
{
|
|
||||||
unsigned total_size;
|
|
||||||
malloc_t *m, *n;
|
|
||||||
int delta;
|
|
||||||
|
|
||||||
if(size == 0)
|
|
||||||
return NULL;
|
|
||||||
total_size = size + sizeof(malloc_t);
|
|
||||||
/* search heap for free block (FIRST FIT) */
|
|
||||||
m = (malloc_t *)g_heap_bot;
|
|
||||||
/* g_heap_bot == 0 == NULL if heap does not yet exist */
|
|
||||||
if(m != NULL)
|
|
||||||
{
|
|
||||||
if(m->magic != MALLOC_MAGIC)
|
|
||||||
// panic("kernel heap is corrupt in kmalloc()");
|
|
||||||
{
|
|
||||||
printf("*** kernel heap is corrupt in kmalloc()\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for(; m->next != NULL; m = m->next)
|
|
||||||
{
|
|
||||||
if(m->used)
|
|
||||||
continue;
|
|
||||||
/* size == m->size is a perfect fit */
|
|
||||||
if(size == m->size)
|
|
||||||
m->used = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* otherwise, we need an extra sizeof(malloc_t) bytes for the header
|
|
||||||
of a second, free block */
|
|
||||||
if(total_size > m->size)
|
|
||||||
continue;
|
|
||||||
/* create a new, smaller free block after this one */
|
|
||||||
n = (malloc_t *)((char *)m + total_size);
|
|
||||||
n->size = m->size - total_size;
|
|
||||||
n->next = m->next;
|
|
||||||
n->magic = MALLOC_MAGIC;
|
|
||||||
n->used = 0;
|
|
||||||
/* reduce the size of this block and mark it used */
|
|
||||||
m->size = size;
|
|
||||||
m->next = n;
|
|
||||||
m->used = 1;
|
|
||||||
}
|
|
||||||
return (char *)m + sizeof(malloc_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* use kbrk() to enlarge (or create!) heap */
|
|
||||||
delta = total_size;
|
|
||||||
n = kbrk(&delta);
|
|
||||||
/* uh-oh */
|
|
||||||
if(n == NULL)
|
|
||||||
return NULL;
|
|
||||||
if(m != NULL)
|
|
||||||
m->next = n;
|
|
||||||
n->size = size;
|
|
||||||
n->magic = MALLOC_MAGIC;
|
|
||||||
n->used = 1;
|
|
||||||
/* did kbrk() return the exact amount of memory we wanted?
|
|
||||||
cast to make "gcc -Wall -W ..." shut the hell up */
|
|
||||||
if((int)total_size == delta)
|
|
||||||
n->next = NULL;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* it returned more than we wanted (it will never return less):
|
|
||||||
create a new, free block */
|
|
||||||
m = (malloc_t *)((char *)n + total_size);
|
|
||||||
m->size = delta - total_size - sizeof(malloc_t);
|
|
||||||
m->next = NULL;
|
|
||||||
m->magic = MALLOC_MAGIC;
|
|
||||||
m->used = 0;
|
|
||||||
|
|
||||||
n->next = m;
|
|
||||||
}
|
|
||||||
return (char *)n + sizeof(malloc_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *kzalloc(size_t size)
|
|
||||||
{
|
|
||||||
void *buf = kmalloc(size);
|
|
||||||
|
|
||||||
memset(buf, 0, size);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
*****************************************************************************/
|
|
||||||
void kfree(void *blk)
|
|
||||||
{
|
|
||||||
malloc_t *m, *n;
|
|
||||||
|
|
||||||
/* get address of header */
|
|
||||||
m = (malloc_t *)((char *)blk - sizeof(malloc_t));
|
|
||||||
if(m->magic != MALLOC_MAGIC)
|
|
||||||
// panic("attempt to kfree() block at 0x%p "
|
|
||||||
// "with bad magic value", blk);
|
|
||||||
{
|
|
||||||
printf("*** attempt to kfree() block at 0x%p "
|
|
||||||
"with bad magic value\n", blk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* find this block in the heap */
|
|
||||||
n = (malloc_t *)g_heap_bot;
|
|
||||||
if(n->magic != MALLOC_MAGIC)
|
|
||||||
// panic("kernel heap is corrupt in kfree()");
|
|
||||||
{
|
|
||||||
printf("*** kernel heap is corrupt in kfree()\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(; n != NULL; n = n->next)
|
|
||||||
{
|
|
||||||
if(n == m)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* not found? bad pointer or no heap or something else? */
|
|
||||||
if(n == NULL)
|
|
||||||
// panic("attempt to kfree() block at 0x%p "
|
|
||||||
// "that is not in the heap", blk);
|
|
||||||
{
|
|
||||||
printf("*** attempt to kfree() block at 0x%p "
|
|
||||||
"that is not in the heap\n", blk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* free the block */
|
|
||||||
m->used = 0;
|
|
||||||
/* coalesce adjacent free blocks
|
|
||||||
Hard to spell, hard to do */
|
|
||||||
for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next)
|
|
||||||
{
|
|
||||||
while(!m->used && m->next != NULL && !m->next->used)
|
|
||||||
{
|
|
||||||
/* resize this block */
|
|
||||||
m->size += sizeof(malloc_t) + m->next->size;
|
|
||||||
/* merge with next block */
|
|
||||||
m->next = m->next->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*****************************************************************************
|
|
||||||
*****************************************************************************/
|
|
||||||
void *krealloc(void *blk, size_t size)
|
|
||||||
{
|
|
||||||
void *new_blk;
|
|
||||||
malloc_t *m;
|
|
||||||
|
|
||||||
/* size == 0: free block */
|
|
||||||
if(size == 0)
|
|
||||||
{
|
|
||||||
if(blk != NULL)
|
|
||||||
kfree(blk);
|
|
||||||
new_blk = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* allocate new block */
|
|
||||||
new_blk = kmalloc(size);
|
|
||||||
/* if allocation OK, and if old block exists, copy old block to new */
|
|
||||||
if(new_blk != NULL && blk != NULL)
|
|
||||||
{
|
|
||||||
m = (malloc_t *)((char *)blk - sizeof(malloc_t));
|
|
||||||
if(m->magic != MALLOC_MAGIC)
|
|
||||||
// panic("attempt to krealloc() block at "
|
|
||||||
// "0x%p with bad magic value", blk);
|
|
||||||
{
|
|
||||||
printf("*** attempt to krealloc() block at "
|
|
||||||
"0x%p with bad magic value\n", blk);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* copy minimum of old and new block sizes */
|
|
||||||
if(size > m->size)
|
|
||||||
size = m->size;
|
|
||||||
memcpy(new_blk, blk, size);
|
|
||||||
/* free the old block */
|
|
||||||
kfree(blk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new_blk;
|
|
||||||
}
|
|
||||||
/*****************************************************************************
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
#include <stdlib.h> /* rand() */
|
|
||||||
|
|
||||||
|
|
||||||
#define SLOTS 17
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
unsigned lifetime[SLOTS];
|
|
||||||
void *blk[SLOTS];
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
dump_heap();
|
|
||||||
memset(lifetime, 0, sizeof(lifetime));
|
|
||||||
memset(blk, 0, sizeof(blk));
|
|
||||||
for(i = 0; i < 1000; i++)
|
|
||||||
{
|
|
||||||
printf("Pass %6u\n", i);
|
|
||||||
for(j = 0; j < SLOTS; j++)
|
|
||||||
{
|
|
||||||
/* age the block */
|
|
||||||
if(lifetime[j] != 0)
|
|
||||||
{
|
|
||||||
(lifetime[j])--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* too old; free it */
|
|
||||||
if(blk[j] != NULL)
|
|
||||||
{
|
|
||||||
kfree(blk[j]);
|
|
||||||
blk[j] = NULL;
|
|
||||||
}
|
|
||||||
/* alloc new block of random size
|
|
||||||
Note that size_t==unsigned, but kmalloc() uses integer math,
|
|
||||||
so block size must be positive integer */
|
|
||||||
#if defined(_32BIT)
|
|
||||||
k = rand() % 40960 + 1;
|
|
||||||
#else
|
|
||||||
k = rand() % 4096 + 1;
|
|
||||||
#endif
|
|
||||||
blk[j] = kmalloc(k);
|
|
||||||
if(blk[j] == NULL)
|
|
||||||
printf("failed to alloc %u bytes\n", k);
|
|
||||||
else
|
|
||||||
/* give it a random lifetime 0-20 */
|
|
||||||
lifetime[j] = rand() % 21;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* let's see what we've wrought */
|
|
||||||
printf("\n\n");
|
|
||||||
dump_heap();
|
|
||||||
/* free everything */
|
|
||||||
for(j = 0; j < SLOTS; j++)
|
|
||||||
{
|
|
||||||
if(blk[j] != NULL)
|
|
||||||
{
|
|
||||||
kfree(blk[j]);
|
|
||||||
blk[j] = NULL;
|
|
||||||
}
|
|
||||||
(lifetime[j]) = 0;
|
|
||||||
}
|
|
||||||
/* after all that, we should have a single, unused block */
|
|
||||||
dump_heap();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
void *b1, *b2, *b3;
|
|
||||||
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
b1 = kmalloc(42);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
b2 = kmalloc(23);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
b3 = kmalloc(7);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
b2 = krealloc(b2, 24);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
kfree(b1);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
b1 = kmalloc(5);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
kfree(b2);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
kfree(b3);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
kfree(b1);
|
|
||||||
dump_heap();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,528 +0,0 @@
|
|||||||
/*
|
|
||||||
* Some syscall stubs
|
|
||||||
*
|
|
||||||
* Copyright (C) 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <l4/api/errno.h>
|
|
||||||
#include <l4lib/types.h>
|
|
||||||
#include <l4lib/ipcdefs.h>
|
|
||||||
#include <l4lib/arch/syscalls.h>
|
|
||||||
#include <l4lib/arch/syslib.h>
|
|
||||||
#include <lib/pathstr.h>
|
|
||||||
#include <lib/malloc.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <task.h>
|
|
||||||
#include <stat.h>
|
|
||||||
#include <vfs.h>
|
|
||||||
#include <alloca.h>
|
|
||||||
#include <path.h>
|
|
||||||
#include <syscalls.h>
|
|
||||||
|
|
||||||
#define NILFD -1
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This informs mm0 about an opened file descriptors.
|
|
||||||
*
|
|
||||||
* MM0 *also* keeps track of fd's because mm0 is a better candidate
|
|
||||||
* for handling syscalls that access file content (i.e. read/write) since
|
|
||||||
* it maintains the page cache. MM0 is not notified about opened files
|
|
||||||
* but is rather informed when it asks to be. This avoids deadlocks by
|
|
||||||
* keeping the request flow in one way.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int pager_sys_open(struct tcb *pager, l4id_t opener, int fd)
|
|
||||||
{
|
|
||||||
struct tcb *task;
|
|
||||||
struct vnode *v;
|
|
||||||
|
|
||||||
//printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
if (pager->tid != PAGER_TID)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check if such task exists */
|
|
||||||
if (!(task = find_task(opener)))
|
|
||||||
return -ESRCH;
|
|
||||||
|
|
||||||
/* Check if that fd has been opened */
|
|
||||||
if (task->files->fd[fd] == NILFD)
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
/* Search the vnode by that vnum */
|
|
||||||
if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb,
|
|
||||||
task->files->fd[fd])))
|
|
||||||
return (int)v;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write file information, they will
|
|
||||||
* be sent via the return origy.
|
|
||||||
*/
|
|
||||||
write_mr(L4SYS_ARG0, v->vnum);
|
|
||||||
write_mr(L4SYS_ARG1, v->size);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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 origy.
|
|
||||||
*/
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
struct dentry *d, *c;
|
|
||||||
|
|
||||||
printf("Vnode names:\n");
|
|
||||||
list_foreach_struct(d, &v->dentries, vref) {
|
|
||||||
printf("%s\n", d->name);
|
|
||||||
printf("Children dentries:\n");
|
|
||||||
list_foreach_struct(c, &d->children, child)
|
|
||||||
printf("%s\n", c->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Creates a node under a directory, e.g. a file, directory. */
|
|
||||||
struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata,
|
|
||||||
unsigned int mode)
|
|
||||||
{
|
|
||||||
struct vnode *vparent, *newnode;
|
|
||||||
const char *nodename;
|
|
||||||
|
|
||||||
/* The last component is to be created */
|
|
||||||
nodename = pathdata_last_component(pdata);
|
|
||||||
|
|
||||||
/* Check that the parent directory exists. */
|
|
||||||
if (IS_ERR(vparent = vfs_lookup_bypath(pdata)))
|
|
||||||
return vparent;
|
|
||||||
|
|
||||||
/* The parent vnode must be a directory. */
|
|
||||||
if (!vfs_isdir(vparent))
|
|
||||||
return PTR_ERR(-ENOENT);
|
|
||||||
|
|
||||||
/* Create new directory under the parent */
|
|
||||||
if (IS_ERR(newnode = vparent->ops.mknod(vparent, nodename, mode)))
|
|
||||||
return newnode;
|
|
||||||
|
|
||||||
// print_vnode(vparent);
|
|
||||||
return newnode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pager notifies vfs about a closed file descriptor.
|
|
||||||
*
|
|
||||||
* FIXME: fsync + close could be done under a single "close" ipc
|
|
||||||
* from pager. Currently there are 2 ipcs: 1 fsync + 1 fd close.
|
|
||||||
*/
|
|
||||||
int pager_sys_close(struct tcb *sender, l4id_t closer, int fd)
|
|
||||||
{
|
|
||||||
struct tcb *task;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
BUG_ON(!(task = find_task(closer)));
|
|
||||||
|
|
||||||
if ((err = id_del(task->files->fdpool, fd)) < 0) {
|
|
||||||
printf("%s: Error releasing fd identifier.\n",
|
|
||||||
__FUNCTION__);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
task->files->fd[fd] = NILFD;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME:
|
|
||||||
* - Is it already open?
|
|
||||||
* - Allocate a copy of path string since lookup destroys it
|
|
||||||
* - Check flags and mode.
|
|
||||||
*/
|
|
||||||
int sys_open(struct tcb *task, const char *pathname, int flags, unsigned int mode)
|
|
||||||
{
|
|
||||||
struct pathdata *pdata;
|
|
||||||
struct vnode *v;
|
|
||||||
int fd;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
/* Parse path data */
|
|
||||||
if (IS_ERR(pdata = pathdata_parse(pathname,
|
|
||||||
alloca(strlen(pathname) + 1),
|
|
||||||
task)))
|
|
||||||
return (int)pdata;
|
|
||||||
|
|
||||||
/* Creating new file */
|
|
||||||
if (flags & O_CREAT) {
|
|
||||||
/* Make sure mode identifies a file */
|
|
||||||
mode |= S_IFREG;
|
|
||||||
if (IS_ERR(v = vfs_create(task, pdata, mode))) {
|
|
||||||
retval = (int)v;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Not creating, just opening, get the vnode */
|
|
||||||
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
|
||||||
retval = (int)v;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a new fd */
|
|
||||||
BUG_ON((fd = id_new(task->files->fdpool)) < 0);
|
|
||||||
retval = fd;
|
|
||||||
|
|
||||||
/* Assign the new fd with the vnode's number */
|
|
||||||
task->files->fd[fd] = v->vnum;
|
|
||||||
|
|
||||||
out:
|
|
||||||
pathdata_destroy(pdata);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sys_mkdir(struct tcb *task, const char *pathname, unsigned int mode)
|
|
||||||
{
|
|
||||||
struct pathdata *pdata;
|
|
||||||
struct vnode *v;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Parse path data */
|
|
||||||
if (IS_ERR(pdata = pathdata_parse(pathname,
|
|
||||||
alloca(strlen(pathname) + 1),
|
|
||||||
task)))
|
|
||||||
return (int)pdata;
|
|
||||||
|
|
||||||
/* Make sure we create a directory */
|
|
||||||
mode |= S_IFDIR;
|
|
||||||
|
|
||||||
/* Create the directory or fail */
|
|
||||||
if (IS_ERR(v = vfs_create(task, pdata, mode)))
|
|
||||||
ret = (int)v;
|
|
||||||
|
|
||||||
/* Destroy extracted path data */
|
|
||||||
pathdata_destroy(pdata);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sys_chdir(struct tcb *task, const char *pathname)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
struct pathdata *pdata;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Parse path data */
|
|
||||||
if (IS_ERR(pdata = pathdata_parse(pathname,
|
|
||||||
alloca(strlen(pathname) + 1),
|
|
||||||
task)))
|
|
||||||
return (int)pdata;
|
|
||||||
|
|
||||||
/* Get the vnode */
|
|
||||||
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
|
||||||
ret = (int)v;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure it's a directory */
|
|
||||||
if (!vfs_isdir(v)) {
|
|
||||||
ret = -ENOTDIR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assign the current directory pointer */
|
|
||||||
task->fs_data->curdir = v;
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* Destroy extracted path data */
|
|
||||||
pathdata_destroy(pdata);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill_kstat(struct vnode *v, struct kstat *ks)
|
|
||||||
{
|
|
||||||
ks->vnum = (u64)v->vnum;
|
|
||||||
ks->mode = v->mode;
|
|
||||||
ks->links = v->links;
|
|
||||||
ks->uid = v->owner & 0xFFFF;
|
|
||||||
ks->gid = (v->owner >> 16) & 0xFFFF;
|
|
||||||
ks->size = v->size;
|
|
||||||
ks->blksize = v->sb->blocksize;
|
|
||||||
ks->atime = v->atime;
|
|
||||||
ks->mtime = v->mtime;
|
|
||||||
ks->ctime = v->ctime;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sys_fstat(struct tcb *task, int fd, void *statbuf)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
unsigned long vnum;
|
|
||||||
|
|
||||||
/* Get the vnum */
|
|
||||||
if (fd < 0 || fd > TASK_FILES_MAX || task->files->fd[fd] == NILFD)
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
vnum = task->files->fd[fd];
|
|
||||||
|
|
||||||
/* Lookup vnode */
|
|
||||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Fill in the c0-style stat structure */
|
|
||||||
fill_kstat(v, statbuf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns codezero-style stat structure which in turn is
|
|
||||||
* converted to posix style stat structure via the libposix
|
|
||||||
* library in userspace.
|
|
||||||
*/
|
|
||||||
int sys_stat(struct tcb *task, const char *pathname, void *statbuf)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
struct pathdata *pdata;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Parse path data */
|
|
||||||
if (IS_ERR(pdata = pathdata_parse(pathname,
|
|
||||||
alloca(strlen(pathname) + 1),
|
|
||||||
task)))
|
|
||||||
return (int)pdata;
|
|
||||||
|
|
||||||
/* Get the vnode */
|
|
||||||
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
|
||||||
ret = (int)v;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill in the c0-style stat structure */
|
|
||||||
fill_kstat(v, statbuf);
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* Destroy extracted path data */
|
|
||||||
pathdata_destroy(pdata);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note this can be solely called by the pager and is not the posix read call.
|
|
||||||
* That call is in the pager. This merely supplies the pages the pager needs
|
|
||||||
* if they're not in the page cache.
|
|
||||||
*/
|
|
||||||
int pager_sys_read(struct tcb *pager, unsigned long vnum, unsigned long f_offset,
|
|
||||||
unsigned long npages, void *pagebuf)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (pager->tid != PAGER_TID)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Lookup vnode */
|
|
||||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Ensure vnode is not a directory */
|
|
||||||
if (vfs_isdir(v))
|
|
||||||
return -EISDIR;
|
|
||||||
|
|
||||||
return v->fops.read(v, f_offset, npages, pagebuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pager_update_stats(struct tcb *pager, unsigned long vnum,
|
|
||||||
unsigned long newsize)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (pager->tid != PAGER_TID)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Lookup vnode */
|
|
||||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
v->size = newsize;
|
|
||||||
v->sb->ops->write_vnode(v->sb, v);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This can be solely called by the pager and is not the posix write call.
|
|
||||||
* That call is in the pager. This writes the dirty pages of a file
|
|
||||||
* back to disk via vfs.
|
|
||||||
*
|
|
||||||
* The buffer must be contiguous by page, if npages > 1.
|
|
||||||
*/
|
|
||||||
int pager_sys_write(struct tcb *pager, unsigned long vnum, unsigned long f_offset,
|
|
||||||
unsigned long npages, void *pagebuf)
|
|
||||||
{
|
|
||||||
struct vnode *v;
|
|
||||||
int ret;
|
|
||||||
int fwrite_end;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (pager->tid != PAGER_TID)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Lookup vnode */
|
|
||||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Ensure vnode is not a directory */
|
|
||||||
if (vfs_isdir(v))
|
|
||||||
return -EISDIR;
|
|
||||||
|
|
||||||
//printf("%s/%s: Writing to vnode %lu, at pgoff 0x%x, %d pages, buf at 0x%x\n",
|
|
||||||
// __TASKNAME__, __FUNCTION__, vnum, f_offset, npages, pagebuf);
|
|
||||||
|
|
||||||
if ((ret = v->fops.write(v, f_offset, npages, pagebuf)) < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the file is extended, write silently extends it.
|
|
||||||
* We update the extended size here. Otherwise subsequent write's
|
|
||||||
* may fail by relying on wrong file size.
|
|
||||||
*/
|
|
||||||
fwrite_end = __pfn_to_addr(f_offset) + ret;
|
|
||||||
if (v->size < fwrite_end) {
|
|
||||||
v->size = fwrite_end;
|
|
||||||
v->sb->ops->write_vnode(v->sb, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: Here's how this should have been:
|
|
||||||
* v->ops.readdir() -> Reads fs-specific directory contents. i.e. reads
|
|
||||||
* the directory buffer, doesn't care however contained vnode details are
|
|
||||||
* stored.
|
|
||||||
*
|
|
||||||
* After reading, it converts the fs-spceific contents into generic vfs
|
|
||||||
* dentries and populates the dentries of those vnodes.
|
|
||||||
*
|
|
||||||
* If vfs_readdir() is issued, those generic dentries are converted into
|
|
||||||
* the posix-defined directory record structure. During this on-the-fly
|
|
||||||
* generation, pseudo-entries such as . and .. are also added.
|
|
||||||
*
|
|
||||||
* If this layering is not done, i.e. the low-level dentry buffer already
|
|
||||||
* keeps this record structure and we try to return that, then we wont
|
|
||||||
* have a chance to add the pseudo-entries . and .. These record entries
|
|
||||||
* are essentially created from parent vnode and current vnode but using
|
|
||||||
* the names . and ..
|
|
||||||
*/
|
|
||||||
|
|
||||||
int fill_dirent(void *buf, unsigned long vnum, int offset, char *name)
|
|
||||||
{
|
|
||||||
struct dirent *d = buf;
|
|
||||||
|
|
||||||
d->inum = (unsigned int)vnum;
|
|
||||||
d->offset = offset;
|
|
||||||
d->rlength = sizeof(struct dirent);
|
|
||||||
strncpy((char *)d->name, name, DIRENT_NAME_MAX);
|
|
||||||
|
|
||||||
return d->rlength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reads @count bytes of posix struct dirents into @buf. This implements
|
|
||||||
* the raw dirent read syscall upon which readdir() etc. posix calls
|
|
||||||
* can be built in userspace.
|
|
||||||
*
|
|
||||||
* FIXME: Ensure buf is in shared utcb, and count does not exceed it.
|
|
||||||
*/
|
|
||||||
int sys_readdir(struct tcb *t, int fd, void *buf, int count)
|
|
||||||
{
|
|
||||||
int dirent_size = sizeof(struct dirent);
|
|
||||||
int total = 0, nbytes = 0;
|
|
||||||
unsigned long vnum;
|
|
||||||
struct vnode *v;
|
|
||||||
struct dentry *d;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
/* Check address is in task's utcb */
|
|
||||||
if ((unsigned long)buf < t->shpage_address ||
|
|
||||||
(unsigned long)buf > t->shpage_address + PAGE_SIZE)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (fd < 0 || fd > TASK_FILES_MAX || t->files->fd[fd] == NILFD)
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
vnum = t->files->fd[fd];
|
|
||||||
|
|
||||||
/* Lookup vnode */
|
|
||||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
d = link_to_struct(v->dentries.next, struct dentry, vref);
|
|
||||||
|
|
||||||
/* Ensure vnode is a directory */
|
|
||||||
if (!vfs_isdir(v))
|
|
||||||
return -ENOTDIR;
|
|
||||||
|
|
||||||
/* Write pseudo-entries . and .. to user buffer */
|
|
||||||
if (count < dirent_size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fill_dirent(buf, v->vnum, nbytes, VFS_STR_CURDIR);
|
|
||||||
nbytes += dirent_size;
|
|
||||||
buf += dirent_size;
|
|
||||||
count -= dirent_size;
|
|
||||||
|
|
||||||
if (count < dirent_size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fill_dirent(buf, d->parent->vnode->vnum, nbytes, VFS_STR_PARDIR);
|
|
||||||
nbytes += dirent_size;
|
|
||||||
buf += dirent_size;
|
|
||||||
count -= dirent_size;
|
|
||||||
|
|
||||||
/* Copy fs-specific dir to buf in struct dirent format */
|
|
||||||
if ((total = v->ops.filldir(buf, v, count)) < 0)
|
|
||||||
return total;
|
|
||||||
|
|
||||||
return nbytes + total;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,315 +0,0 @@
|
|||||||
/*
|
|
||||||
* FS0 task data initialisation.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2008 Bahadir Balban
|
|
||||||
*/
|
|
||||||
#include <l4/macros.h>
|
|
||||||
#include <l4/lib/list.h>
|
|
||||||
#include <l4/api/errno.h>
|
|
||||||
#include <l4lib/arch/syscalls.h>
|
|
||||||
#include <l4lib/arch/syslib.h>
|
|
||||||
#include <l4lib/arch/utcb.h>
|
|
||||||
#include <l4lib/ipcdefs.h>
|
|
||||||
#include <lib/malloc.h>
|
|
||||||
#include <lib/idpool.h>
|
|
||||||
#include <task.h>
|
|
||||||
#include <vfs.h>
|
|
||||||
#include <sys/ipc.h>
|
|
||||||
#include <sys/shm.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <syscalls.h>
|
|
||||||
#include <globals.h>
|
|
||||||
|
|
||||||
|
|
||||||
extern void *shared_page;
|
|
||||||
|
|
||||||
struct global_list global_tasks = {
|
|
||||||
.list = { &global_tasks.list, &global_tasks.list },
|
|
||||||
.total = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
void global_add_task(struct tcb *task)
|
|
||||||
{
|
|
||||||
BUG_ON(!list_empty(&task->list));
|
|
||||||
list_insert_tail(&task->list, &global_tasks.list);
|
|
||||||
global_tasks.total++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void global_remove_task(struct tcb *task)
|
|
||||||
{
|
|
||||||
BUG_ON(list_empty(&task->list));
|
|
||||||
list_remove_init(&task->list);
|
|
||||||
BUG_ON(--global_tasks.total < 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tcb *find_task(int tid)
|
|
||||||
{
|
|
||||||
struct tcb *t;
|
|
||||||
|
|
||||||
list_foreach_struct(t, &global_tasks.list, list)
|
|
||||||
if (t->tid == tid)
|
|
||||||
return t;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a vfs task structure according to given flags */
|
|
||||||
struct tcb *tcb_alloc_init(unsigned int flags)
|
|
||||||
{
|
|
||||||
struct tcb *task;
|
|
||||||
|
|
||||||
if (!(task = kzalloc(sizeof(struct tcb))))
|
|
||||||
return PTR_ERR(-ENOMEM);
|
|
||||||
|
|
||||||
/* Allocate new fs data struct if its not shared */
|
|
||||||
if (!(flags & TCB_SHARED_FS)) {
|
|
||||||
if (!(task->fs_data =
|
|
||||||
kzalloc(sizeof(*task->fs_data)))) {
|
|
||||||
kfree(task);
|
|
||||||
return PTR_ERR(-ENOMEM);
|
|
||||||
}
|
|
||||||
task->fs_data->tcb_refs = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate file structures if not shared */
|
|
||||||
if (!(flags & TCB_SHARED_FILES)) {
|
|
||||||
if (!(task->files =
|
|
||||||
kzalloc(sizeof(*task->files)))) {
|
|
||||||
kfree(task->fs_data);
|
|
||||||
kfree(task);
|
|
||||||
return PTR_ERR(-ENOMEM);
|
|
||||||
}
|
|
||||||
if (IS_ERR(task->files->fdpool =
|
|
||||||
id_pool_new_init(TASK_FILES_MAX))) {
|
|
||||||
void *err = task->files->fdpool;
|
|
||||||
|
|
||||||
kfree(task->files);
|
|
||||||
kfree(task->fs_data);
|
|
||||||
kfree(task);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
task->files->tcb_refs = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ids will be set up later */
|
|
||||||
task->tid = TASK_ID_INVALID;
|
|
||||||
|
|
||||||
/* Initialise list structure */
|
|
||||||
link_init(&task->list);
|
|
||||||
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_tcb(struct tcb *to, struct tcb *from, unsigned int share_flags)
|
|
||||||
{
|
|
||||||
if (share_flags & TCB_SHARED_FILES) {
|
|
||||||
to->files = from->files;
|
|
||||||
to->files->tcb_refs++;
|
|
||||||
} else {
|
|
||||||
/* Copy all file descriptors */
|
|
||||||
memcpy(to->files->fd, from->files->fd,
|
|
||||||
TASK_FILES_MAX * sizeof(to->files->fd[0]));
|
|
||||||
|
|
||||||
/* Copy the idpool */
|
|
||||||
id_pool_copy(to->files->fdpool, from->files->fdpool, TASK_FILES_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (share_flags & TCB_SHARED_FS) {
|
|
||||||
to->fs_data = from->fs_data;
|
|
||||||
to->fs_data->tcb_refs++;
|
|
||||||
} else
|
|
||||||
memcpy(to->fs_data, from->fs_data, sizeof(*to->fs_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a task struct and initialise it */
|
|
||||||
struct tcb *tcb_create(struct tcb *orig, l4id_t tid, unsigned long shpage,
|
|
||||||
unsigned int share_flags)
|
|
||||||
{
|
|
||||||
struct tcb *task;
|
|
||||||
|
|
||||||
/* Can't have some share flags with no original task */
|
|
||||||
BUG_ON(!orig && share_flags);
|
|
||||||
|
|
||||||
/* Create a task and use given space and thread ids. */
|
|
||||||
if (IS_ERR(task = tcb_alloc_init(share_flags)))
|
|
||||||
return task;
|
|
||||||
|
|
||||||
task->tid = tid;
|
|
||||||
task->shpage_address = shpage;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there's an original task that means this will be a full
|
|
||||||
* or partial copy of it. We copy depending on share_flags.
|
|
||||||
*/
|
|
||||||
if (orig)
|
|
||||||
copy_tcb(task, orig, share_flags);
|
|
||||||
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free shared structures if no references left */
|
|
||||||
void tcb_free_resources(struct tcb *task)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (--task->fs_data->tcb_refs == 0)
|
|
||||||
kfree(task->fs_data);
|
|
||||||
|
|
||||||
if (--task->files->tcb_refs == 0) {
|
|
||||||
kfree(task->files->fdpool);
|
|
||||||
kfree(task->files);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void tcb_destroy(struct tcb *task)
|
|
||||||
{
|
|
||||||
global_remove_task(task);
|
|
||||||
|
|
||||||
tcb_free_resources(task);
|
|
||||||
|
|
||||||
kfree(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Attaches to task's utcb. TODO: Add SHM_RDONLY and test it.
|
|
||||||
* FIXME: This calls the pager and is a potential for deadlock
|
|
||||||
* it only doesn't lock because it is called during initialisation.
|
|
||||||
*/
|
|
||||||
int task_utcb_attach(struct tcb *t)
|
|
||||||
{
|
|
||||||
int shmid;
|
|
||||||
void *shmaddr;
|
|
||||||
|
|
||||||
/* Use it as a key to create a shared memory region */
|
|
||||||
if ((shmid = shmget((key_t)t->shpage_address, PAGE_SIZE, 0)) == -1)
|
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
/* Attach to the region */
|
|
||||||
if ((int)(shmaddr = shmat(shmid, (void *)t->shpage_address, 0)) == -1)
|
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
/* Ensure address is right */
|
|
||||||
if ((unsigned long)shmaddr != t->shpage_address)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
// printf("%s: Mapped shared page of task %d @ 0x%x\n",
|
|
||||||
// __TASKNAME__, t->tid, shmaddr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_err:
|
|
||||||
printf("%s: Mapping utcb of task %d failed with err: %d.\n",
|
|
||||||
__TASKNAME__, t->tid, errno);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Receives ipc from pager about a new fork event and
|
|
||||||
* the information on the resulting child task.
|
|
||||||
*/
|
|
||||||
int pager_notify_fork(struct tcb *sender, l4id_t parentid,
|
|
||||||
l4id_t childid, unsigned long shpage_address,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
struct tcb *child, *parent;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
BUG_ON(!(parent = find_task(parentid)));
|
|
||||||
|
|
||||||
/* Create a child vfs tcb using given parent and copy flags */
|
|
||||||
if (IS_ERR(child = tcb_create(parent, childid, shpage_address, flags)))
|
|
||||||
return (int)child;
|
|
||||||
|
|
||||||
global_add_task(child);
|
|
||||||
|
|
||||||
// printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pager tells us that a task is exiting by this call.
|
|
||||||
*/
|
|
||||||
int pager_notify_exit(struct tcb *sender, l4id_t tid)
|
|
||||||
{
|
|
||||||
struct tcb *task;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
BUG_ON(!(task = find_task(tid)));
|
|
||||||
|
|
||||||
tcb_destroy(task);
|
|
||||||
|
|
||||||
// printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Read task information into the utcb page, since it won't fit into mrs. */
|
|
||||||
struct task_data_head *receive_pager_taskdata(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Make the actual ipc call */
|
|
||||||
if ((err = l4_sendrecv(PAGER_TID, PAGER_TID,
|
|
||||||
L4_IPC_TAG_TASKDATA)) < 0) {
|
|
||||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
|
|
||||||
return PTR_ERR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if call itself was successful */
|
|
||||||
if ((err = l4_get_retval()) < 0) {
|
|
||||||
printf("%s: Error: %d.\n", __FUNCTION__, err);
|
|
||||||
return PTR_ERR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Data is expected in the utcb page */
|
|
||||||
// printf("%s: %d Total tasks.\n", __FUNCTION__,
|
|
||||||
// ((struct task_data_head *)shared_page)->total);
|
|
||||||
|
|
||||||
return (struct task_data_head *)shared_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int init_task_structs(struct task_data_head *tdata_head)
|
|
||||||
{
|
|
||||||
struct tcb *t;
|
|
||||||
|
|
||||||
for (int i = 0; i < tdata_head->total; i++) {
|
|
||||||
/* New tcb with fields sent by pager */
|
|
||||||
if (IS_ERR(t = tcb_create(0, tdata_head->tdata[i].tid,
|
|
||||||
tdata_head->tdata[i].shpage_address,
|
|
||||||
0)))
|
|
||||||
return (int)t;
|
|
||||||
|
|
||||||
/* Initialise vfs specific fields. */
|
|
||||||
t->fs_data->rootdir = vfs_root.pivot;
|
|
||||||
t->fs_data->curdir = vfs_root.pivot;
|
|
||||||
|
|
||||||
/* Print task information */
|
|
||||||
//printf("%s: Task info received from mm0:\n", __TASKNAME__);
|
|
||||||
//printf("%s: task id: %d, utcb address: 0x%x\n",
|
|
||||||
// __TASKNAME__, t->tid, t->utcb_address);
|
|
||||||
|
|
||||||
/* shm attach to the utcbs for all these tasks except own */
|
|
||||||
if (t->tid != self_tid())
|
|
||||||
task_utcb_attach(t);
|
|
||||||
global_add_task(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_task_data(void)
|
|
||||||
{
|
|
||||||
struct task_data_head *tdata_head;
|
|
||||||
|
|
||||||
/* Read how many tasks and tids of each */
|
|
||||||
BUG_ON((tdata_head = receive_pager_taskdata()) < 0);
|
|
||||||
|
|
||||||
/* Initialise local task structs using this info */
|
|
||||||
BUG_ON(init_task_structs(tdata_head) < 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
compiler_prefix = "arm-linux-"
|
|
||||||
objdump = "objdump"
|
|
||||||
command = "-t"
|
|
||||||
image_name = "roottask.axf"
|
|
||||||
linkoutput_file_suffix = "-linkinfo.txt"
|
|
||||||
linkoutput_file = image_name + linkoutput_file_suffix
|
|
||||||
def generate_bootdesc():
|
|
||||||
command = compiler_prefix + objdump + " -t " + image_name + " > " + linkoutput_file
|
|
||||||
print command
|
|
||||||
os.system(command)
|
|
||||||
f = open(linkoutput_file, "r")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
line = f.readline()
|
|
||||||
if len(line) is 0:
|
|
||||||
break
|
|
||||||
if "_start" in line or "_end" in line:
|
|
||||||
print line
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_bootdesc()
|
|
||||||
|
|
||||||
@@ -29,11 +29,12 @@ def generate_lma_lds(target, source, env):
|
|||||||
|
|
||||||
lma_lds = Command('include/linker.lds', 'include/linker.lds.in', generate_lma_lds)
|
lma_lds = Command('include/linker.lds', 'include/linker.lds.in', generate_lma_lds)
|
||||||
|
|
||||||
src = [Glob('*.c') + Glob('src/*.c') + Glob('src/lib/*.c') + Glob('src/lib/elf/*.c') + Glob('src/arch/*.c')]
|
src = [Glob('*.c') + Glob('mm/*.c') + Glob('lib/*.c') + Glob('fs/*.c') + Glob('fs/memfs/*.c') + Glob('lib/elf/*.c') + Glob('mm/arch/*.c')]
|
||||||
|
|
||||||
e = env.Clone()
|
e = env.Clone()
|
||||||
|
|
||||||
e.Append(LINKFLAGS = ['-T' + lma_lds[0].path, '-u_start'])
|
e.Append(LINKFLAGS = ['-T' + lma_lds[0].path, '-u_start'])
|
||||||
|
e.Append(LIBS = 'posix')
|
||||||
objs = e.Object(src)
|
objs = e.Object(src)
|
||||||
mm0 = e.Program('mm0.elf', objs)
|
mm0 = e.Program('mm0.elf', objs)
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,6 @@ int initialise(void)
|
|||||||
|
|
||||||
printf("%s: Mounted memfs root filesystem.\n", __TASKNAME__);
|
printf("%s: Mounted memfs root filesystem.\n", __TASKNAME__);
|
||||||
|
|
||||||
/* Learn about what tasks are running */
|
|
||||||
init_task_data();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialisation is done. From here on, we can start
|
* Initialisation is done. From here on, we can start
|
||||||
* serving filesystem requests.
|
* serving filesystem requests.
|
||||||
@@ -11,14 +11,6 @@
|
|||||||
LINK_DECLARE(vnode_cache);
|
LINK_DECLARE(vnode_cache);
|
||||||
LINK_DECLARE(dentry_cache);
|
LINK_DECLARE(dentry_cache);
|
||||||
|
|
||||||
/*
|
|
||||||
* /
|
|
||||||
* /boot
|
|
||||||
* /boot/images/mm0.axf
|
|
||||||
* /boot/images/fs0.axf
|
|
||||||
* /boot/images/test0.axf
|
|
||||||
* /file.txt
|
|
||||||
*/
|
|
||||||
struct vfs_mountpoint vfs_root;
|
struct vfs_mountpoint vfs_root;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -9,8 +9,8 @@ int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
|
|||||||
int nbits);
|
int nbits);
|
||||||
int check_and_clear_bit(u32 *word, int bit);
|
int check_and_clear_bit(u32 *word, int bit);
|
||||||
int check_and_clear_contig_bits(u32 *word, int first, int nbits);
|
int check_and_clear_contig_bits(u32 *word, int first, int nbits);
|
||||||
int check_and_set_bit(u32 *word, int bit);
|
|
||||||
|
|
||||||
|
int check_and_set_bit(u32 *word, int bit);
|
||||||
|
|
||||||
/* Set */
|
/* Set */
|
||||||
static inline void setbit(unsigned int *w, unsigned int flags)
|
static inline void setbit(unsigned int *w, unsigned int flags)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <lib/bit.h>
|
#include <lib/bit.h>
|
||||||
#include <lib/spinlock.h>
|
#include <lib/spinlock.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include INC_GLUE(memory.h)
|
||||||
|
|
||||||
struct id_pool {
|
struct id_pool {
|
||||||
int nwords;
|
int nwords;
|
||||||
@@ -10,6 +12,14 @@ struct id_pool {
|
|||||||
u32 bitmap[];
|
u32 bitmap[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Copy one id pool to another by calculating its size */
|
||||||
|
static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int totalbits)
|
||||||
|
{
|
||||||
|
int nwords = BITWISE_GETWORD(totalbits);
|
||||||
|
|
||||||
|
memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool));
|
||||||
|
}
|
||||||
|
|
||||||
struct id_pool *id_pool_new_init(int mapsize);
|
struct id_pool *id_pool_new_init(int mapsize);
|
||||||
int id_new(struct id_pool *pool);
|
int id_new(struct id_pool *pool);
|
||||||
int id_del(struct id_pool *pool, int id);
|
int id_del(struct id_pool *pool, int id);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void *kmalloc(size_t size);
|
void *kmalloc(size_t size);
|
||||||
void kfree(void *blk);
|
void kfree(void *blk);
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
#ifndef __MM0_SPINLOCK_H__
|
#ifndef __MM0_SPINLOCK_H__
|
||||||
#define __MM0_SPINLOCK_H__
|
#define __MM0_SPINLOCK_H__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct spinlock {
|
struct spinlock {
|
||||||
int lock;
|
int lock;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ SECTIONS
|
|||||||
.data : AT (ADDR(.data) - pager_offset)
|
.data : AT (ADDR(.data) - pager_offset)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
|
_start_bdev = .;
|
||||||
|
*(.data.memfs)
|
||||||
|
_end_bdev = .;
|
||||||
}
|
}
|
||||||
.bss : AT (ADDR(.bss) - pager_offset) { *(.bss) }
|
.bss : AT (ADDR(.bss) - pager_offset) { *(.bss) }
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
|
|||||||
@@ -36,5 +36,30 @@ int sys_fork(struct tcb *parent);
|
|||||||
int sys_clone(struct tcb *parent, void *child_stack, unsigned int clone_flags);
|
int sys_clone(struct tcb *parent, void *child_stack, unsigned int clone_flags);
|
||||||
void sys_exit(struct tcb *task, int status);
|
void sys_exit(struct tcb *task, int status);
|
||||||
|
|
||||||
|
/* Posix calls */
|
||||||
|
int sys_open(struct tcb *sender, const char *pathname, int flags, u32 mode);
|
||||||
|
int sys_readdir(struct tcb *sender, int fd, void *buf, int count);
|
||||||
|
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);
|
||||||
|
|
||||||
|
int pager_sys_write(struct tcb *sender, unsigned long vnum, unsigned long f_offset,
|
||||||
|
unsigned long npages, void *pagebuf);
|
||||||
|
|
||||||
|
int pager_sys_close(struct tcb *sender, l4id_t closer, int fd);
|
||||||
|
int pager_update_stats(struct tcb *sender, unsigned long vnum,
|
||||||
|
unsigned long newsize);
|
||||||
|
|
||||||
|
int pager_notify_fork(struct tcb *sender, l4id_t parentid,
|
||||||
|
l4id_t childid, unsigned long utcb_address,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
|
int pager_notify_exit(struct tcb *sender, l4id_t tid);
|
||||||
|
|
||||||
#endif /* __MM0_SYSARGS_H__ */
|
#endif /* __MM0_SYSARGS_H__ */
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ struct file_descriptor {
|
|||||||
|
|
||||||
struct task_fd_head {
|
struct task_fd_head {
|
||||||
struct file_descriptor fd[TASK_FILES_MAX];
|
struct file_descriptor fd[TASK_FILES_MAX];
|
||||||
|
struct id_pool *fdpool;
|
||||||
int tcb_refs;
|
int tcb_refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,6 +56,18 @@ struct task_vma_head {
|
|||||||
int tcb_refs;
|
int tcb_refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TCB_NO_SHARING 0
|
||||||
|
#define TCB_SHARED_VM (1 << 0)
|
||||||
|
#define TCB_SHARED_FILES (1 << 1)
|
||||||
|
#define TCB_SHARED_FS (1 << 2)
|
||||||
|
#define TASK_FILES_MAX 32
|
||||||
|
|
||||||
|
struct task_fs_data {
|
||||||
|
struct vnode *curdir;
|
||||||
|
struct vnode *rootdir;
|
||||||
|
int tcb_refs;
|
||||||
|
};
|
||||||
|
|
||||||
struct utcb_desc {
|
struct utcb_desc {
|
||||||
struct link list;
|
struct link list;
|
||||||
unsigned long utcb_base;
|
unsigned long utcb_base;
|
||||||
@@ -114,9 +127,6 @@ struct tcb {
|
|||||||
unsigned long map_start;
|
unsigned long map_start;
|
||||||
unsigned long map_end;
|
unsigned long map_end;
|
||||||
|
|
||||||
/* Default ipc-shared-page information */
|
|
||||||
void *shared_page;
|
|
||||||
|
|
||||||
/* Chain of utcb descriptors */
|
/* Chain of utcb descriptors */
|
||||||
struct utcb_head *utcb_head;
|
struct utcb_head *utcb_head;
|
||||||
|
|
||||||
@@ -128,6 +138,8 @@ struct tcb {
|
|||||||
|
|
||||||
/* File descriptors for this task */
|
/* File descriptors for this task */
|
||||||
struct task_fd_head *files;
|
struct task_fd_head *files;
|
||||||
|
struct task_fs_data *fs_data;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcb_head {
|
struct tcb_head {
|
||||||
|
|||||||
+16
-9
@@ -84,11 +84,6 @@ void handle_requests(void)
|
|||||||
ret = page_fault_handler(sender, (fault_kdata_t *)&mr[0]);
|
ret = page_fault_handler(sender, (fault_kdata_t *)&mr[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L4_IPC_TAG_TASKDATA:
|
|
||||||
/* Send runnable task information to fs0 */
|
|
||||||
ret = vfs_send_task_data(sender);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L4_IPC_TAG_SHMGET: {
|
case L4_IPC_TAG_SHMGET: {
|
||||||
ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]);
|
ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]);
|
||||||
break;
|
break;
|
||||||
@@ -103,10 +98,6 @@ void handle_requests(void)
|
|||||||
ret = sys_shmdt(sender, (void *)mr[0]);
|
ret = sys_shmdt(sender, (void *)mr[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L4_IPC_TAG_SHPAGE:
|
|
||||||
ret = (int)task_send_shpage_address(sender, (l4id_t)mr[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L4_IPC_TAG_READ:
|
case L4_IPC_TAG_READ:
|
||||||
ret = sys_read(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
|
ret = sys_read(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
|
||||||
break;
|
break;
|
||||||
@@ -166,6 +157,22 @@ void handle_requests(void)
|
|||||||
// ret = sys_brk(sender, (void *)mr[0]);
|
// ret = sys_brk(sender, (void *)mr[0]);
|
||||||
// break;
|
// break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: Fix all these syscalls to read any buffer data from the caller task's utcb. */
|
||||||
|
/* FS0 System calls */
|
||||||
|
case L4_IPC_TAG_OPEN:
|
||||||
|
ret = sys_open(sender, (void *)mr[0], (int)mr[1], (unsigned int)mr[2]);
|
||||||
|
break;
|
||||||
|
case L4_IPC_TAG_MKDIR:
|
||||||
|
ret = sys_mkdir(sender, (const char *)mr[0], (unsigned int)mr[1]);
|
||||||
|
break;
|
||||||
|
case L4_IPC_TAG_CHDIR:
|
||||||
|
ret = sys_chdir(sender, (const char *)mr[0]);
|
||||||
|
break;
|
||||||
|
case L4_IPC_TAG_READDIR:
|
||||||
|
ret = sys_readdir(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("%s: Unrecognised ipc tag (%d) "
|
printf("%s: Unrecognised ipc tag (%d) "
|
||||||
"received from (%d). Full mr reading: "
|
"received from (%d). Full mr reading: "
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ int boottask_setup_regions(struct vm_file *file, struct tcb *task,
|
|||||||
int boottask_mmap_regions(struct tcb *task, struct vm_file *file)
|
int boottask_mmap_regions(struct tcb *task, struct vm_file *file)
|
||||||
{
|
{
|
||||||
void *mapped;
|
void *mapped;
|
||||||
struct vm_file *shm;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mmap each task's physical image to task's address space.
|
* mmap each task's physical image to task's address space.
|
||||||
@@ -74,14 +73,6 @@ int boottask_mmap_regions(struct tcb *task, struct vm_file *file)
|
|||||||
return (int)mapped;
|
return (int)mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Task's default shared page */
|
|
||||||
task->shared_page = shm_new_address(DEFAULT_SHPAGE_SIZE/PAGE_SIZE);
|
|
||||||
|
|
||||||
/* Create a shared memory segment available for shmat() */
|
|
||||||
if (IS_ERR(shm = shm_new((key_t)task->shared_page,
|
|
||||||
__pfn(DEFAULT_SHPAGE_SIZE))))
|
|
||||||
return (int)shm;
|
|
||||||
|
|
||||||
task_setup_utcb(task);
|
task_setup_utcb(task);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -16,42 +16,6 @@
|
|||||||
#include <test.h>
|
#include <test.h>
|
||||||
#include <clone.h>
|
#include <clone.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Sends vfs task information about forked child, and its utcb
|
|
||||||
*/
|
|
||||||
int vfs_notify_fork(struct tcb *child, struct tcb *parent, unsigned int flags)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
l4_save_ipcregs();
|
|
||||||
|
|
||||||
/* Write parent and child information */
|
|
||||||
write_mr(L4SYS_ARG0, parent->tid);
|
|
||||||
write_mr(L4SYS_ARG1, child->tid);
|
|
||||||
write_mr(L4SYS_ARG2, (unsigned int)child->shared_page);
|
|
||||||
write_mr(L4SYS_ARG3, flags);
|
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID,
|
|
||||||
L4_IPC_TAG_NOTIFY_FORK)) < 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: Pager from VFS read error: %d.\n",
|
|
||||||
__FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int sys_fork(struct tcb *parent)
|
int sys_fork(struct tcb *parent)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -88,15 +52,13 @@ int sys_fork(struct tcb *parent)
|
|||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
/* Create and prefault a shared page for child and map it to vfs task */
|
/* Create and prefault a shared page for child and map it to vfs task */
|
||||||
shpage_map_to_task(child, find_task(VFS_TID),
|
BUG();
|
||||||
SHPAGE_NEW_ADDRESS | SHPAGE_NEW_SHM |
|
//shpage_map_to_task(child, find_task(VFS_TID),
|
||||||
SHPAGE_PREFAULT);
|
// SHPAGE_NEW_ADDRESS | SHPAGE_NEW_SHM |
|
||||||
|
// SHPAGE_PREFAULT);
|
||||||
|
|
||||||
// printf("Mapped 0x%p to vfs as utcb of %d\n", child->utcb, child->tid);
|
// printf("Mapped 0x%p to vfs as utcb of %d\n", child->utcb, child->tid);
|
||||||
|
|
||||||
/* We can now notify vfs about forked process */
|
|
||||||
vfs_notify_fork(child, parent, TCB_NO_SHARING);
|
|
||||||
|
|
||||||
/* Add child to global task list */
|
/* Add child to global task list */
|
||||||
global_add_task(child);
|
global_add_task(child);
|
||||||
|
|
||||||
@@ -146,12 +108,13 @@ int do_clone(struct tcb *parent, unsigned long child_stack, unsigned int flags)
|
|||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
/* Create and prefault a shared page for child and map it to vfs task */
|
/* Create and prefault a shared page for child and map it to vfs task */
|
||||||
shpage_map_to_task(child, find_task(VFS_TID),
|
BUG();
|
||||||
SHPAGE_NEW_ADDRESS | SHPAGE_NEW_SHM |
|
//shpage_map_to_task(child, find_task(VFS_TID),
|
||||||
SHPAGE_PREFAULT);
|
// SHPAGE_NEW_ADDRESS | SHPAGE_NEW_SHM |
|
||||||
|
// SHPAGE_PREFAULT);
|
||||||
|
|
||||||
/* We can now notify vfs about forked process */
|
/* We can now notify vfs about forked process */
|
||||||
vfs_notify_fork(child, parent, flags);
|
BUG();
|
||||||
|
|
||||||
/* Add child to global task list */
|
/* Add child to global task list */
|
||||||
global_add_task(child);
|
global_add_task(child);
|
||||||
@@ -18,39 +18,6 @@
|
|||||||
#include <lib/malloc.h>
|
#include <lib/malloc.h>
|
||||||
#include <l4/api/space.h>
|
#include <l4/api/space.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Sends vfs task information about forked child, and its utcb
|
|
||||||
*/
|
|
||||||
int vfs_notify_exit(struct tcb *task, int status)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
|
||||||
|
|
||||||
l4_save_ipcregs();
|
|
||||||
|
|
||||||
/* Write parent and child information */
|
|
||||||
write_mr(L4SYS_ARG0, task->tid);
|
|
||||||
write_mr(L4SYS_ARG1, status);
|
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID,
|
|
||||||
L4_IPC_TAG_NOTIFY_EXIT)) < 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 returned ipc error: %d.\n",
|
|
||||||
__FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Closes all file descriptors of a task */
|
/* Closes all file descriptors of a task */
|
||||||
int task_close_files(struct tcb *task)
|
int task_close_files(struct tcb *task)
|
||||||
@@ -91,7 +58,10 @@ int execve_recycle_task(struct tcb *new, struct tcb *orig)
|
|||||||
new->pagerid = orig->pagerid;
|
new->pagerid = orig->pagerid;
|
||||||
|
|
||||||
/* Copy shared page */
|
/* Copy shared page */
|
||||||
new->shared_page = orig->shared_page;
|
/*
|
||||||
|
* FIXME: Make sure to take care of this.
|
||||||
|
*/
|
||||||
|
//new->shared_page = orig->shared_page;
|
||||||
|
|
||||||
/* Copy parent relationship */
|
/* Copy parent relationship */
|
||||||
BUG_ON(new->parent);
|
BUG_ON(new->parent);
|
||||||
@@ -135,12 +105,10 @@ void do_exit(struct tcb *task, int status)
|
|||||||
/* Destroy task's utcb slot */
|
/* Destroy task's utcb slot */
|
||||||
task_destroy_utcb(task);
|
task_destroy_utcb(task);
|
||||||
|
|
||||||
/* Tell vfs that task is exiting */
|
|
||||||
vfs_notify_exit(task, status);
|
|
||||||
|
|
||||||
/* Remove default shared page shm areas from vfs */
|
/* Remove default shared page shm areas from vfs */
|
||||||
|
BUG();
|
||||||
// printf("Unmapping 0x%p from vfs as shared-page of %d\n", task->shared_page, task->tid);
|
// printf("Unmapping 0x%p from vfs as shared-page of %d\n", task->shared_page, task->tid);
|
||||||
shpage_unmap_from_task(task, find_task(VFS_TID));
|
//shpage_unmap_from_task(task, find_task(VFS_TID));
|
||||||
|
|
||||||
/* Free task's local tcb */
|
/* Free task's local tcb */
|
||||||
tcb_destroy(task);
|
tcb_destroy(task);
|
||||||
@@ -21,6 +21,15 @@
|
|||||||
#include <user.h>
|
#include <user.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
|
||||||
|
#include <lib/pathstr.h>
|
||||||
|
#include <lib/malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <task.h>
|
||||||
|
#include <stat.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <path.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
/* Copy from one page's buffer into another page */
|
/* Copy from one page's buffer into another page */
|
||||||
int page_copy(struct page *dst, struct page *src,
|
int page_copy(struct page *dst, struct page *src,
|
||||||
@@ -56,34 +65,35 @@ int page_copy(struct page *dst, struct page *src,
|
|||||||
int vfs_read(unsigned long vnum, unsigned long file_offset,
|
int vfs_read(unsigned long vnum, unsigned long file_offset,
|
||||||
unsigned long npages, void *pagebuf)
|
unsigned long npages, void *pagebuf)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct vnode *v;
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
/* Lookup vnode */
|
||||||
|
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
l4_save_ipcregs();
|
/* Ensure vnode is not a directory */
|
||||||
|
if (vfs_isdir(v))
|
||||||
|
return -EISDIR;
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, vnum);
|
return v->fops.read(v, file_offset, npages, pagebuf);
|
||||||
write_mr(L4SYS_ARG1, file_offset);
|
|
||||||
write_mr(L4SYS_ARG2, npages);
|
|
||||||
write_mr(L4SYS_ARG3, (u32)pagebuf);
|
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_PAGER_READ)) < 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: Error: %d.\n",
|
|
||||||
__FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Directories only for now */
|
||||||
|
void print_vnode(struct vnode *v)
|
||||||
|
{
|
||||||
|
struct dentry *d, *c;
|
||||||
|
|
||||||
|
printf("Vnode names:\n");
|
||||||
|
list_foreach_struct(d, &v->dentries, vref) {
|
||||||
|
printf("%s\n", d->name);
|
||||||
|
printf("Children dentries:\n");
|
||||||
|
list_foreach_struct(c, &d->children, child)
|
||||||
|
printf("%s\n", c->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Different from vfs_open(), which validates an already opened
|
* Different from vfs_open(), which validates an already opened
|
||||||
* file descriptor, this call opens a new vfs file by the pager
|
* file descriptor, this call opens a new vfs file by the pager
|
||||||
@@ -92,46 +102,31 @@ out:
|
|||||||
*/
|
*/
|
||||||
int vfs_open_bypath(const char *pathname, unsigned long *vnum, unsigned long *length)
|
int vfs_open_bypath(const char *pathname, unsigned long *vnum, unsigned long *length)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct pathdata *pdata;
|
||||||
struct tcb *vfs;
|
struct tcb *task;
|
||||||
|
struct vnode *v;
|
||||||
|
int retval;
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
/* Parse path data */
|
||||||
|
if (IS_ERR(pdata = pathdata_parse(pathname,
|
||||||
|
alloca(strlen(pathname) + 1),
|
||||||
|
task)))
|
||||||
|
return (int)pdata;
|
||||||
|
|
||||||
if (!(vfs = find_task(VFS_TID)))
|
/* Search the vnode by that path */
|
||||||
return -ESRCH;
|
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
||||||
|
retval = (int)v;
|
||||||
/*
|
|
||||||
* Copy string to vfs shared page.
|
|
||||||
*
|
|
||||||
* FIXME: There's a chance we're overwriting other tasks'
|
|
||||||
* ipc information that is on the vfs shared page.
|
|
||||||
*/
|
|
||||||
strcpy(vfs->shared_page + 0x200, pathname);
|
|
||||||
|
|
||||||
l4_save_ipcregs();
|
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, (unsigned long)vfs->shared_page + 0x200);
|
|
||||||
|
|
||||||
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if syscall was successful */
|
*vnum = v->vnum;
|
||||||
if ((err = l4_get_retval()) < 0) {
|
*length = v->size;
|
||||||
printf("%s: VFS open error: %d.\n",
|
|
||||||
__FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read file information */
|
return 0;
|
||||||
*vnum = read_mr(L4SYS_ARG0);
|
|
||||||
*length = read_mr(L4SYS_ARG1);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
l4_restore_ipcregs();
|
pathdata_destroy(pdata);
|
||||||
return err;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -142,32 +137,229 @@ out:
|
|||||||
*/
|
*/
|
||||||
int vfs_open(l4id_t opener, int fd, unsigned long *vnum, unsigned long *length)
|
int vfs_open(l4id_t opener, int fd, unsigned long *vnum, unsigned long *length)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct tcb *task;
|
||||||
|
struct vnode *v;
|
||||||
|
|
||||||
l4_save_ipcregs();
|
/* Check if such task exists */
|
||||||
|
if (!(task = find_task(opener)))
|
||||||
|
return -ESRCH;
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, opener);
|
/* Check if that fd has been opened */
|
||||||
write_mr(L4SYS_ARG1, fd);
|
if (!task->files->fd[fd].vnum)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_PAGER_OPEN)) < 0) {
|
/* Search the vnode by that vnum */
|
||||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
|
if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb,
|
||||||
goto out;
|
task->files->fd[fd].vnum)))
|
||||||
}
|
return (int)v;
|
||||||
|
|
||||||
/* 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 */
|
/* Read file information */
|
||||||
*vnum = read_mr(L4SYS_ARG0);
|
*vnum = v->vnum;
|
||||||
*length = read_mr(L4SYS_ARG1);
|
*length = v->size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates a node under a directory, e.g. a file, directory. */
|
||||||
|
struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata,
|
||||||
|
unsigned int mode)
|
||||||
|
{
|
||||||
|
struct vnode *vparent, *newnode;
|
||||||
|
const char *nodename;
|
||||||
|
|
||||||
|
/* The last component is to be created */
|
||||||
|
nodename = pathdata_last_component(pdata);
|
||||||
|
|
||||||
|
/* Check that the parent directory exists. */
|
||||||
|
if (IS_ERR(vparent = vfs_lookup_bypath(pdata)))
|
||||||
|
return vparent;
|
||||||
|
|
||||||
|
/* The parent vnode must be a directory. */
|
||||||
|
if (!vfs_isdir(vparent))
|
||||||
|
return PTR_ERR(-ENOENT);
|
||||||
|
|
||||||
|
/* Create new directory under the parent */
|
||||||
|
if (IS_ERR(newnode = vparent->ops.mknod(vparent, nodename, mode)))
|
||||||
|
return newnode;
|
||||||
|
|
||||||
|
// print_vnode(vparent);
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME:
|
||||||
|
* - Is it already open?
|
||||||
|
* - Allocate a copy of path string since lookup destroys it
|
||||||
|
* - Check flags and mode.
|
||||||
|
*/
|
||||||
|
int sys_open(struct tcb *task, const char *pathname, int flags, unsigned int mode)
|
||||||
|
{
|
||||||
|
struct pathdata *pdata;
|
||||||
|
struct vnode *v;
|
||||||
|
int fd;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* Parse path data */
|
||||||
|
if (IS_ERR(pdata = pathdata_parse(pathname,
|
||||||
|
alloca(strlen(pathname) + 1),
|
||||||
|
task)))
|
||||||
|
return (int)pdata;
|
||||||
|
|
||||||
|
/* Creating new file */
|
||||||
|
if (flags & O_CREAT) {
|
||||||
|
/* Make sure mode identifies a file */
|
||||||
|
mode |= S_IFREG;
|
||||||
|
if (IS_ERR(v = vfs_create(task, pdata, mode))) {
|
||||||
|
retval = (int)v;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Not creating, just opening, get the vnode */
|
||||||
|
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
||||||
|
retval = (int)v;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a new fd */
|
||||||
|
BUG_ON((fd = id_new(task->files->fdpool)) < 0);
|
||||||
|
retval = fd;
|
||||||
|
|
||||||
|
/* Why assign just vnum? Why not vmfile, vnode etc? */
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
/* Assign the new fd with the vnode's number */
|
||||||
|
task->files->fd[fd].vnum = v->vnum;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
l4_restore_ipcregs();
|
pathdata_destroy(pdata);
|
||||||
return err;
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_mkdir(struct tcb *task, const char *pathname, unsigned int mode)
|
||||||
|
{
|
||||||
|
struct pathdata *pdata;
|
||||||
|
struct vnode *v;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Parse path data */
|
||||||
|
if (IS_ERR(pdata = pathdata_parse(pathname,
|
||||||
|
alloca(strlen(pathname) + 1),
|
||||||
|
task)))
|
||||||
|
return (int)pdata;
|
||||||
|
|
||||||
|
/* Make sure we create a directory */
|
||||||
|
mode |= S_IFDIR;
|
||||||
|
|
||||||
|
/* Create the directory or fail */
|
||||||
|
if (IS_ERR(v = vfs_create(task, pdata, mode)))
|
||||||
|
ret = (int)v;
|
||||||
|
|
||||||
|
/* Destroy extracted path data */
|
||||||
|
pathdata_destroy(pdata);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_chdir(struct tcb *task, const char *pathname)
|
||||||
|
{
|
||||||
|
struct vnode *v;
|
||||||
|
struct pathdata *pdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Parse path data */
|
||||||
|
if (IS_ERR(pdata = pathdata_parse(pathname,
|
||||||
|
alloca(strlen(pathname) + 1),
|
||||||
|
task)))
|
||||||
|
return (int)pdata;
|
||||||
|
|
||||||
|
/* Get the vnode */
|
||||||
|
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
||||||
|
ret = (int)v;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure it's a directory */
|
||||||
|
if (!vfs_isdir(v)) {
|
||||||
|
ret = -ENOTDIR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign the current directory pointer */
|
||||||
|
task->fs_data->curdir = v;
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* Destroy extracted path data */
|
||||||
|
pathdata_destroy(pdata);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_kstat(struct vnode *v, struct kstat *ks)
|
||||||
|
{
|
||||||
|
ks->vnum = (u64)v->vnum;
|
||||||
|
ks->mode = v->mode;
|
||||||
|
ks->links = v->links;
|
||||||
|
ks->uid = v->owner & 0xFFFF;
|
||||||
|
ks->gid = (v->owner >> 16) & 0xFFFF;
|
||||||
|
ks->size = v->size;
|
||||||
|
ks->blksize = v->sb->blocksize;
|
||||||
|
ks->atime = v->atime;
|
||||||
|
ks->mtime = v->mtime;
|
||||||
|
ks->ctime = v->ctime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_fstat(struct tcb *task, int fd, void *statbuf)
|
||||||
|
{
|
||||||
|
struct vnode *v;
|
||||||
|
unsigned long vnum;
|
||||||
|
|
||||||
|
/* Get the vnum */
|
||||||
|
if (fd < 0 || fd > TASK_FILES_MAX || !task->files->fd[fd].vnum)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
BUG(); /* Could just return vmfile->vnode here. */
|
||||||
|
vnum = task->files->fd[fd].vnum;
|
||||||
|
|
||||||
|
/* Lookup vnode */
|
||||||
|
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Fill in the c0-style stat structure */
|
||||||
|
fill_kstat(v, statbuf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns codezero-style stat structure which in turn is
|
||||||
|
* converted to posix style stat structure via the libposix
|
||||||
|
* library in userspace.
|
||||||
|
*/
|
||||||
|
int sys_stat(struct tcb *task, const char *pathname, void *statbuf)
|
||||||
|
{
|
||||||
|
struct vnode *v;
|
||||||
|
struct pathdata *pdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Parse path data */
|
||||||
|
if (IS_ERR(pdata = pathdata_parse(pathname,
|
||||||
|
alloca(strlen(pathname) + 1),
|
||||||
|
task)))
|
||||||
|
return (int)pdata;
|
||||||
|
|
||||||
|
/* Get the vnode */
|
||||||
|
if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
|
||||||
|
ret = (int)v;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill in the c0-style stat structure */
|
||||||
|
fill_kstat(v, statbuf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* Destroy extracted path data */
|
||||||
|
pathdata_destroy(pdata);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -357,89 +549,62 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The buffer must be contiguous by page, if npages > 1.
|
||||||
|
*/
|
||||||
int vfs_write(unsigned long vnum, unsigned long file_offset,
|
int vfs_write(unsigned long vnum, unsigned long file_offset,
|
||||||
unsigned long npages, void *pagebuf)
|
unsigned long npages, void *pagebuf)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct vnode *v;
|
||||||
|
int fwrite_end;
|
||||||
|
int ret;
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
||||||
l4_save_ipcregs();
|
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, vnum);
|
/* Lookup vnode */
|
||||||
write_mr(L4SYS_ARG1, file_offset);
|
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||||
write_mr(L4SYS_ARG2, npages);
|
return -EINVAL;
|
||||||
write_mr(L4SYS_ARG3, (u32)pagebuf);
|
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_PAGER_WRITE)) < 0) {
|
/* Ensure vnode is not a directory */
|
||||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
|
if (vfs_isdir(v))
|
||||||
goto out;
|
return -EISDIR;
|
||||||
|
|
||||||
|
//printf("%s/%s: Writing to vnode %lu, at pgoff 0x%x, %d pages, buf at 0x%x\n",
|
||||||
|
// __TASKNAME__, __FUNCTION__, vnum, f_offset, npages, pagebuf);
|
||||||
|
|
||||||
|
if ((ret = v->fops.write(v, file_offset, npages, pagebuf)) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the file is extended, write silently extends it.
|
||||||
|
* We update the extended size here. Otherwise subsequent write's
|
||||||
|
* may fail by relying on wrong file size.
|
||||||
|
*/
|
||||||
|
fwrite_end = __pfn_to_addr(file_offset) + ret;
|
||||||
|
if (v->size < fwrite_end) {
|
||||||
|
v->size = fwrite_end;
|
||||||
|
v->sb->ops->write_vnode(v->sb, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if syscall was successful */
|
return ret;
|
||||||
if ((err = l4_get_retval()) < 0) {
|
|
||||||
printf("%s: Pager to VFS write error: %d.\n", __FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_close(l4id_t sender, int fd)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
// printf("%s/%s Sending to %d\n", __TASKNAME__, __FUNCTION__, VFS_TID);
|
|
||||||
l4_save_ipcregs();
|
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, sender);
|
|
||||||
write_mr(L4SYS_ARG1, fd);
|
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_PAGER_CLOSE)) < 0) {
|
|
||||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
// printf("%s/%s Received from %d\n", __TASKNAME__, __FUNCTION__, VFS_TID);
|
|
||||||
|
|
||||||
/* Check if syscall was successful */
|
|
||||||
if ((err = l4_get_retval()) < 0) {
|
|
||||||
printf("%s: Pager to VFS write error: %d.\n", __FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes updated file stats back to vfs. (e.g. new file size) */
|
/* Writes updated file stats back to vfs. (e.g. new file size) */
|
||||||
int vfs_update_file_stats(struct vm_file *f)
|
int vfs_update_file_stats(struct vm_file *f)
|
||||||
{
|
{
|
||||||
int err = 0;
|
unsigned long vnum = vm_file_to_vnum(f);
|
||||||
|
struct vnode *v;
|
||||||
|
|
||||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
/* Lookup vnode */
|
||||||
l4_save_ipcregs();
|
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
write_mr(L4SYS_ARG0, vm_file_to_vnum(f));
|
v->size = f->length;
|
||||||
write_mr(L4SYS_ARG1, f->length);
|
v->sb->ops->write_vnode(v->sb, v);
|
||||||
|
|
||||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID,
|
return 0;
|
||||||
L4_IPC_TAG_PAGER_UPDATE_STATS)) < 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: Pager to VFS write error: %d.\n",
|
|
||||||
__FUNCTION__, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
l4_restore_ipcregs();
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Writes pages in cache back to their file */
|
/* Writes pages in cache back to their file */
|
||||||
@@ -518,15 +683,24 @@ void vm_file_put(struct vm_file *file)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: fsync + close could be done under a single "close" ipc
|
||||||
|
* from pager. Currently there are 2 ipcs: 1 fsync + 1 fd close.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Closes the file descriptor and notifies vfs */
|
/* Closes the file descriptor and notifies vfs */
|
||||||
int do_close(struct tcb *task, int fd)
|
int do_close(struct tcb *task, int fd)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// printf("%s: Closing fd: %d on task %d\n", __FUNCTION__,
|
printf("%s: Closing fd: %d on task %d\n", __FUNCTION__,
|
||||||
// fd, task->tid);
|
fd, task->tid);
|
||||||
if ((err = vfs_close(task->tid, fd)) < 0)
|
|
||||||
|
if ((err = id_del(task->files->fdpool, fd)) < 0) {
|
||||||
|
printf("%s: Error releasing fd identifier.\n",
|
||||||
|
__FUNCTION__);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there was no IO on it, we may not know the file,
|
* If there was no IO on it, we may not know the file,
|
||||||
@@ -991,3 +1165,95 @@ int sys_lseek(struct tcb *task, int fd, off_t offset, int whence)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: Here's how this should have been:
|
||||||
|
* v->ops.readdir() -> Reads fs-specific directory contents. i.e. reads
|
||||||
|
* the directory buffer, doesn't care however contained vnode details are
|
||||||
|
* stored.
|
||||||
|
*
|
||||||
|
* After reading, it converts the fs-spceific contents into generic vfs
|
||||||
|
* dentries and populates the dentries of those vnodes.
|
||||||
|
*
|
||||||
|
* If vfs_readdir() is issued, those generic dentries are converted into
|
||||||
|
* the posix-defined directory record structure. During this on-the-fly
|
||||||
|
* generation, pseudo-entries such as . and .. are also added.
|
||||||
|
*
|
||||||
|
* If this layering is not done, i.e. the low-level dentry buffer already
|
||||||
|
* keeps this record structure and we try to return that, then we wont
|
||||||
|
* have a chance to add the pseudo-entries . and .. These record entries
|
||||||
|
* are essentially created from parent vnode and current vnode but using
|
||||||
|
* the names . and ..
|
||||||
|
*/
|
||||||
|
|
||||||
|
int fill_dirent(void *buf, unsigned long vnum, int offset, char *name)
|
||||||
|
{
|
||||||
|
struct dirent *d = buf;
|
||||||
|
|
||||||
|
d->inum = (unsigned int)vnum;
|
||||||
|
d->offset = offset;
|
||||||
|
d->rlength = sizeof(struct dirent);
|
||||||
|
strncpy((char *)d->name, name, DIRENT_NAME_MAX);
|
||||||
|
|
||||||
|
return d->rlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads @count bytes of posix struct dirents into @buf. This implements
|
||||||
|
* the raw dirent read syscall upon which readdir() etc. posix calls
|
||||||
|
* can be built in userspace.
|
||||||
|
*
|
||||||
|
* FIXME: Ensure buf is in shared utcb, and count does not exceed it.
|
||||||
|
*/
|
||||||
|
int sys_readdir(struct tcb *t, int fd, void *buf, int count)
|
||||||
|
{
|
||||||
|
int dirent_size = sizeof(struct dirent);
|
||||||
|
int total = 0, nbytes = 0;
|
||||||
|
unsigned long vnum;
|
||||||
|
struct vnode *v;
|
||||||
|
struct dentry *d;
|
||||||
|
|
||||||
|
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
||||||
|
|
||||||
|
BUG(); /* Do this by extended ipc !!! */
|
||||||
|
/* Check address is in task's utcb */
|
||||||
|
|
||||||
|
if (fd < 0 || fd > TASK_FILES_MAX || !t->files->fd[fd].vnum)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
vnum = t->files->fd[fd].vnum;
|
||||||
|
|
||||||
|
/* Lookup vnode */
|
||||||
|
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
d = link_to_struct(v->dentries.next, struct dentry, vref);
|
||||||
|
|
||||||
|
/* Ensure vnode is a directory */
|
||||||
|
if (!vfs_isdir(v))
|
||||||
|
return -ENOTDIR;
|
||||||
|
|
||||||
|
/* Write pseudo-entries . and .. to user buffer */
|
||||||
|
if (count < dirent_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fill_dirent(buf, v->vnum, nbytes, VFS_STR_CURDIR);
|
||||||
|
nbytes += dirent_size;
|
||||||
|
buf += dirent_size;
|
||||||
|
count -= dirent_size;
|
||||||
|
|
||||||
|
if (count < dirent_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fill_dirent(buf, d->parent->vnode->vnum, nbytes, VFS_STR_PARDIR);
|
||||||
|
nbytes += dirent_size;
|
||||||
|
buf += dirent_size;
|
||||||
|
count -= dirent_size;
|
||||||
|
|
||||||
|
/* Copy fs-specific dir to buf in struct dirent format */
|
||||||
|
if ((total = v->ops.filldir(buf, v, count)) < 0)
|
||||||
|
return total;
|
||||||
|
|
||||||
|
return nbytes + total;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <boot.h>
|
#include <boot.h>
|
||||||
#include <utcb.h>
|
#include <utcb.h>
|
||||||
#include <bootm.h>
|
#include <bootm.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
/* A separate list than the generic file list that keeps just the boot files */
|
/* A separate list than the generic file list that keeps just the boot files */
|
||||||
LINK_DECLARE(boot_file_list);
|
LINK_DECLARE(boot_file_list);
|
||||||
@@ -97,6 +98,10 @@ int mm0_task_init(struct vm_file *f, unsigned long task_start,
|
|||||||
task->spid = ids->spid;
|
task->spid = ids->spid;
|
||||||
task->tgid = ids->tgid;
|
task->tgid = ids->tgid;
|
||||||
|
|
||||||
|
/* Initialise vfs specific fields. */
|
||||||
|
task->fs_data->rootdir = vfs_root.pivot;
|
||||||
|
task->fs_data->curdir = vfs_root.pivot;
|
||||||
|
|
||||||
if ((err = boottask_setup_regions(f, task,
|
if ((err = boottask_setup_regions(f, task,
|
||||||
task_start, task_end)) < 0)
|
task_start, task_end)) < 0)
|
||||||
return err;
|
return err;
|
||||||
@@ -61,7 +61,6 @@ int default_release_pages(struct vm_object *vm_obj)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int file_page_out(struct vm_object *vm_obj, unsigned long page_offset)
|
int file_page_out(struct vm_object *vm_obj, unsigned long page_offset)
|
||||||
{
|
{
|
||||||
struct vm_file *f = vm_object_to_file(vm_obj);
|
struct vm_file *f = vm_object_to_file(vm_obj);
|
||||||
@@ -88,11 +87,14 @@ int file_page_out(struct vm_object *vm_obj, unsigned long page_offset)
|
|||||||
paddr = (void *)page_to_phys(page);
|
paddr = (void *)page_to_phys(page);
|
||||||
vaddr = l4_new_virtual(1);
|
vaddr = l4_new_virtual(1);
|
||||||
|
|
||||||
/* Map the page to vfs task */
|
/* FIXME: Are we sure that pages need to be mapped to self one-by-one? */
|
||||||
l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, VFS_TID);
|
BUG();
|
||||||
|
|
||||||
// printf("%s/%s: Writing to vnode %d, at pgoff 0x%x, %d pages, buf at 0x%x\n",
|
/* Map the page to self */
|
||||||
// __TASKNAME__, __FUNCTION__, vm_file_to_vnum(f), page_offset, 1, vaddr);
|
l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, self_tid());
|
||||||
|
|
||||||
|
printf("%s/%s: Writing to vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n",
|
||||||
|
__TASKNAME__, __FUNCTION__, vm_file_to_vnum(f), page_offset, 1, vaddr);
|
||||||
|
|
||||||
/* Syscall to vfs to write page back to file. */
|
/* Syscall to vfs to write page back to file. */
|
||||||
if ((err = vfs_write(vm_file_to_vnum(f), page_offset, 1, vaddr)) < 0)
|
if ((err = vfs_write(vm_file_to_vnum(f), page_offset, 1, vaddr)) < 0)
|
||||||
@@ -226,28 +226,6 @@ struct vm_file *shm_new(key_t key, unsigned long npages)
|
|||||||
return shm_file;
|
return shm_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Fast internal path to do shmget/shmat() together for mm0's
|
|
||||||
* convenience. Works for existing areas.
|
|
||||||
*/
|
|
||||||
void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr)
|
|
||||||
{
|
|
||||||
struct vm_file *shm_file;
|
|
||||||
struct shm_descriptor *shm_desc;
|
|
||||||
|
|
||||||
list_foreach_struct(shm_file, &global_vm_files.list, list) {
|
|
||||||
if(shm_file->type == VM_FILE_SHM) {
|
|
||||||
shm_desc = shm_file_to_desc(shm_file);
|
|
||||||
/* Found the key, shmat that area */
|
|
||||||
if (shm_desc->key == key)
|
|
||||||
return do_shmat(shm_file, shmaddr,
|
|
||||||
0, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PTR_ERR(-EEXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: Make sure hostile tasks don't subvert other tasks' shared pages
|
* FIXME: Make sure hostile tasks don't subvert other tasks' shared pages
|
||||||
* by early-registring their shared page address here.
|
* by early-registring their shared page address here.
|
||||||
@@ -308,6 +286,30 @@ int sys_shmget(key_t key, int size, int shmflg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fast internal path to do shmget/shmat() together for mm0's
|
||||||
|
* convenience. Works for existing areas.
|
||||||
|
*/
|
||||||
|
void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr)
|
||||||
|
{
|
||||||
|
struct vm_file *shm_file;
|
||||||
|
struct shm_descriptor *shm_desc;
|
||||||
|
|
||||||
|
list_foreach_struct(shm_file, &global_vm_files.list, list) {
|
||||||
|
if(shm_file->type == VM_FILE_SHM) {
|
||||||
|
shm_desc = shm_file_to_desc(shm_file);
|
||||||
|
/* Found the key, shmat that area */
|
||||||
|
if (shm_desc->key == key)
|
||||||
|
return do_shmat(shm_file, shmaddr,
|
||||||
|
0, task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PTR_ERR(-EEXIST);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently, a default shm page is allocated to every thread in the system
|
* Currently, a default shm page is allocated to every thread in the system
|
||||||
* for efficient ipc communication. This part below provides the allocation
|
* for efficient ipc communication. This part below provides the allocation
|
||||||
@@ -379,3 +381,4 @@ int shpage_unmap_from_task(struct tcb *owner, struct tcb *mapper)
|
|||||||
{
|
{
|
||||||
return sys_shmdt(mapper, owner->shared_page);
|
return sys_shmdt(mapper, owner->shared_page);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <boot.h>
|
#include <boot.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
#include <utcb.h>
|
#include <utcb.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
struct global_list global_tasks = {
|
struct global_list global_tasks = {
|
||||||
.list = { &global_tasks.list, &global_tasks.list },
|
.list = { &global_tasks.list, &global_tasks.list },
|
||||||
@@ -74,6 +75,7 @@ struct tcb *find_task(int tid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct tcb *tcb_alloc_init(unsigned int flags)
|
struct tcb *tcb_alloc_init(unsigned int flags)
|
||||||
{
|
{
|
||||||
struct tcb *task;
|
struct tcb *task;
|
||||||
@@ -102,15 +104,40 @@ struct tcb *tcb_alloc_init(unsigned int flags)
|
|||||||
link_init(&task->utcb_head->list);
|
link_init(&task->utcb_head->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate new fs data struct if its not shared */
|
||||||
|
if (!(flags & TCB_SHARED_FS)) {
|
||||||
|
if (!(task->fs_data =
|
||||||
|
kzalloc(sizeof(*task->fs_data)))) {
|
||||||
|
kfree(task->vm_area_head);
|
||||||
|
kfree(task->utcb_head);
|
||||||
|
kfree(task);
|
||||||
|
return PTR_ERR(-ENOMEM);
|
||||||
|
}
|
||||||
|
task->fs_data->tcb_refs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate file structures if not shared */
|
/* Allocate file structures if not shared */
|
||||||
if (!(flags & TCB_SHARED_FILES)) {
|
if (!(flags & TCB_SHARED_FILES)) {
|
||||||
if (!(task->files =
|
if (!(task->files =
|
||||||
kzalloc(sizeof(*task->files)))) {
|
kzalloc(sizeof(*task->files)))) {
|
||||||
kfree(task->vm_area_head);
|
kfree(task->vm_area_head);
|
||||||
kfree(task->utcb_head);
|
kfree(task->utcb_head);
|
||||||
|
kfree(task->fs_data);
|
||||||
kfree(task);
|
kfree(task);
|
||||||
|
|
||||||
return PTR_ERR(-ENOMEM);
|
return PTR_ERR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
if (IS_ERR(task->files->fdpool =
|
||||||
|
id_pool_new_init(TASK_FILES_MAX))) {
|
||||||
|
void *err = task->files->fdpool;
|
||||||
|
kfree(task->vm_area_head);
|
||||||
|
kfree(task->utcb_head);
|
||||||
|
kfree(task->fs_data);
|
||||||
|
kfree(task->files);
|
||||||
|
kfree(task);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
task->files->tcb_refs = 1;
|
task->files->tcb_refs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,8 +164,14 @@ int task_free_resources(struct tcb *task)
|
|||||||
* Threads may share file descriptor structure
|
* Threads may share file descriptor structure
|
||||||
* if no users left, free it.
|
* if no users left, free it.
|
||||||
*/
|
*/
|
||||||
if (!(--task->files->tcb_refs))
|
if (--task->files->tcb_refs == 0) {
|
||||||
|
kfree(task->files->fdpool);
|
||||||
kfree(task->files);
|
kfree(task->files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Similarly free filesystem view structure */
|
||||||
|
if (--task->fs_data->tcb_refs == 0)
|
||||||
|
kfree(task->fs_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Threads may share the virtual space.
|
* Threads may share the virtual space.
|
||||||
@@ -246,7 +279,7 @@ int task_release_vmas(struct task_vma_head *vma_head)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
|
int copy_tcb(struct tcb *to, struct tcb *from, unsigned int share_flags)
|
||||||
{
|
{
|
||||||
/* Copy program segment boundary information */
|
/* Copy program segment boundary information */
|
||||||
to->start = from->start;
|
to->start = from->start;
|
||||||
@@ -267,7 +300,7 @@ int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
|
|||||||
to->map_end = from->map_end;
|
to->map_end = from->map_end;
|
||||||
|
|
||||||
/* Sharing the list of vmas and utcbs */
|
/* Sharing the list of vmas and utcbs */
|
||||||
if (flags & TCB_SHARED_VM) {
|
if (share_flags & TCB_SHARED_VM) {
|
||||||
to->vm_area_head = from->vm_area_head;
|
to->vm_area_head = from->vm_area_head;
|
||||||
to->vm_area_head->tcb_refs++;
|
to->vm_area_head->tcb_refs++;
|
||||||
to->utcb_head = from->utcb_head;
|
to->utcb_head = from->utcb_head;
|
||||||
@@ -283,13 +316,16 @@ int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy all file descriptors */
|
if (share_flags & TCB_SHARED_FILES) {
|
||||||
if (flags & TCB_SHARED_FILES) {
|
|
||||||
to->files = from->files;
|
to->files = from->files;
|
||||||
to->files->tcb_refs++;
|
to->files->tcb_refs++;
|
||||||
} else {
|
} else {
|
||||||
/* Bulk copy all file descriptors */
|
/* Copy all file descriptors */
|
||||||
memcpy(to->files, from->files, sizeof(*to->files));
|
memcpy(to->files->fd, from->files->fd,
|
||||||
|
TASK_FILES_MAX * sizeof(to->files->fd[0]));
|
||||||
|
|
||||||
|
/* Copy the idpool */
|
||||||
|
id_pool_copy(to->files->fdpool, from->files->fdpool, TASK_FILES_MAX);
|
||||||
|
|
||||||
/* Increase refcount for all open files */
|
/* Increase refcount for all open files */
|
||||||
for (int i = 0; i < TASK_FILES_MAX; i++)
|
for (int i = 0; i < TASK_FILES_MAX; i++)
|
||||||
@@ -297,6 +333,12 @@ int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
|
|||||||
to->files->fd[i].vmfile->openers++;
|
to->files->fd[i].vmfile->openers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share_flags & TCB_SHARED_FS) {
|
||||||
|
to->fs_data = from->fs_data;
|
||||||
|
to->fs_data->tcb_refs++;
|
||||||
|
} else
|
||||||
|
memcpy(to->fs_data, from->fs_data, sizeof(*to->fs_data));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,6 +348,9 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids,
|
|||||||
struct tcb *task;
|
struct tcb *task;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
/* Can't have some share flags with no parent task */
|
||||||
|
BUG_ON(!parent && share_flags);
|
||||||
|
|
||||||
/* Set task ids if a parent is supplied */
|
/* Set task ids if a parent is supplied */
|
||||||
if (parent) {
|
if (parent) {
|
||||||
ids->tid = parent->tid;
|
ids->tid = parent->tid;
|
||||||
@@ -369,6 +414,10 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids,
|
|||||||
} else {
|
} else {
|
||||||
struct tcb *pager = find_task(PAGER_TID);
|
struct tcb *pager = find_task(PAGER_TID);
|
||||||
|
|
||||||
|
/* Initialise vfs specific fields. */
|
||||||
|
task->fs_data->rootdir = vfs_root.pivot;
|
||||||
|
task->fs_data->curdir = vfs_root.pivot;
|
||||||
|
|
||||||
/* All parentless tasks are children of the pager */
|
/* All parentless tasks are children of the pager */
|
||||||
list_insert_tail(&task->child_ref, &pager->children);
|
list_insert_tail(&task->child_ref, &pager->children);
|
||||||
task->parent = pager;
|
task->parent = pager;
|
||||||
@@ -643,46 +692,6 @@ int task_start(struct tcb *task)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* During its initialisation FS0 wants to learn how many boot tasks
|
|
||||||
* are running, and their tids, which includes itself. This function
|
|
||||||
* provides that information.
|
|
||||||
*/
|
|
||||||
int vfs_send_task_data(struct tcb *vfs)
|
|
||||||
{
|
|
||||||
int li = 0;
|
|
||||||
struct tcb *t, *self;
|
|
||||||
struct task_data_head *tdata_head;
|
|
||||||
|
|
||||||
if (vfs->tid != VFS_TID) {
|
|
||||||
printf("%s: Task data requested by %d, which is not "
|
|
||||||
"FS0 id %d, ignoring.\n", __TASKNAME__, vfs->tid,
|
|
||||||
VFS_TID);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BUG_ON(!(self = find_task(self_tid())));
|
|
||||||
BUG_ON(!vfs->shared_page);
|
|
||||||
|
|
||||||
/* Attach mm0 to vfs's utcb segment just like a normal task */
|
|
||||||
shpage_map_to_task(vfs, self, SHPAGE_PREFAULT);
|
|
||||||
|
|
||||||
/* Write all requested task information to shared pages's user buffer area */
|
|
||||||
tdata_head = (struct task_data_head *)vfs->shared_page;
|
|
||||||
|
|
||||||
/* First word is total number of tcbs */
|
|
||||||
tdata_head->total = global_tasks.total;
|
|
||||||
|
|
||||||
/* Write per-task data for all tasks */
|
|
||||||
list_foreach_struct(t, &global_tasks.list, list) {
|
|
||||||
tdata_head->tdata[li].tid = t->tid;
|
|
||||||
tdata_head->tdata[li].shpage_address = (unsigned long)t->shared_page;
|
|
||||||
li++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prefaults all mapped regions of a task. The reason we have this is
|
* Prefaults all mapped regions of a task. The reason we have this is
|
||||||
* some servers are in the page fault handling path (e.g. fs0), and we
|
* some servers are in the page fault handling path (e.g. fs0), and we
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Australian Public Licence B (OZPLB)
|
|
||||||
*
|
|
||||||
* Version 1-0
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004 National ICT Australia
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
|
|
||||||
* National ICT Australia
|
|
||||||
* http://www.ertos.nicta.com.au
|
|
||||||
*
|
|
||||||
* Permission is granted by National ICT Australia, free of charge, to
|
|
||||||
* any person obtaining a copy of this software and any associated
|
|
||||||
* documentation files (the "Software") to deal with the Software without
|
|
||||||
* restriction, including (without limitation) the rights to use, copy,
|
|
||||||
* modify, adapt, merge, publish, distribute, communicate to the public,
|
|
||||||
* sublicense, and/or sell, lend or rent out copies of the Software, and
|
|
||||||
* to permit persons to whom the Software is furnished to do so, subject
|
|
||||||
* to the following conditions:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimers.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above
|
|
||||||
* copyright notice, this list of conditions and the following
|
|
||||||
* disclaimers in the documentation and/or other materials provided
|
|
||||||
* with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of National ICT Australia, nor the names of its
|
|
||||||
* contributors, may be used to endorse or promote products derived
|
|
||||||
* from this Software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
|
|
||||||
* PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
|
|
||||||
* NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
||||||
* BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
|
|
||||||
* REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
|
|
||||||
* THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
|
|
||||||
* ERRORS, WHETHER OR NOT DISCOVERABLE.
|
|
||||||
*
|
|
||||||
* TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
|
|
||||||
* NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
|
|
||||||
* THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
|
|
||||||
* NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
|
|
||||||
* OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
|
|
||||||
* OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
|
|
||||||
* OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
|
|
||||||
* CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
|
|
||||||
* CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
|
|
||||||
* DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
|
|
||||||
* CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
|
|
||||||
* DAMAGES OR OTHER LIABILITY.
|
|
||||||
*
|
|
||||||
* If applicable legislation implies representations, warranties, or
|
|
||||||
* conditions, or imposes obligations or liability on National ICT
|
|
||||||
* Australia or one of its contributors in respect of the Software that
|
|
||||||
* cannot be wholly or partly excluded, restricted or modified, the
|
|
||||||
* liability of National ICT Australia or the contributor is limited, to
|
|
||||||
* the full extent permitted by the applicable legislation, at its
|
|
||||||
* option, to:
|
|
||||||
* a. in the case of goods, any one or more of the following:
|
|
||||||
* i. the replacement of the goods or the supply of equivalent goods;
|
|
||||||
* ii. the repair of the goods;
|
|
||||||
* iii. the payment of the cost of replacing the goods or of acquiring
|
|
||||||
* equivalent goods;
|
|
||||||
* iv. the payment of the cost of having the goods repaired; or
|
|
||||||
* b. in the case of services:
|
|
||||||
* i. the supplying of the services again; or
|
|
||||||
* ii. the payment of the cost of having the services supplied again.
|
|
||||||
*
|
|
||||||
* The construction, validity and performance of this licence is governed
|
|
||||||
* by the laws in force in New South Wales, Australia.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __thumb__
|
|
||||||
#define bl blx
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.section .text.head
|
|
||||||
.code 32
|
|
||||||
.global _start;
|
|
||||||
.align;
|
|
||||||
_start:
|
|
||||||
ldr sp, =__stack
|
|
||||||
bl platform_init
|
|
||||||
bl __container_init
|
|
||||||
1:
|
|
||||||
b 1b
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user