Finished adding untested bare functionality vfs

Finished adding untested shm syscalls.
Finished adding untested l4 send/recv helpers

Everything compiles. Now going to fix lots of bugs ;-)
This commit is contained in:
Bahadir Balban
2008-02-03 17:42:38 +00:00
parent 05e9028e90
commit cab2e8bdd3
51 changed files with 1661 additions and 227 deletions

View File

@@ -1,19 +1,27 @@
#ifndef __BLKDEV_H__
#define __BLKDEV_H__
#include <l4lib/types.h>
struct block_device;
struct block_device_ops {
void (*open)(struct block_device *bdev);
void (*read)(unsigned long offset, int size, void *buf);
void (*write)(unsigned long offset, int size, void *buf);
void (*read_page)(unsigned long pfn, void *buf);
void (*write_page)(unsigned long pfn, void *buf);
int (*init)(struct block_device *bdev);
int (*open)(struct block_device *bdev);
int (*read)(struct block_device *bdev, unsigned long offset,
int size, void *buf);
int (*write)(struct block_device *bdev, unsigned long offset,
int size, void *buf);
int (*read_page)(struct block_device *bdev,
unsigned long pfn, void *buf);
int (*write_page)(struct block_device *bdev,
unsigned long pfn, void *buf);
};
struct block_device {
char *name;
unsigned long size;
void *private; /* Low-level device specific data */
u64 size;
struct block_device_ops ops;
};

View File

@@ -1,6 +1,7 @@
#ifndef __RAMDISK_H__
#define __RAMDISK_H__
extern struct block_device ramdisk[];
extern struct block_device ramdisk[];
#endif

View File

@@ -1,10 +1,59 @@
/*
* High-level block device handling.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#include <stdio.h>
#include <blkdev.h>
/*
* Handles block device requests from fs0 using a combination of
* server-specific and posix shm semantics
*/
void handle_block_device_request()
{
u32 mr[MR_UNUSED_TOTAL];
l4id_t sender;
int err;
u32 tag;
printf("%s: Listening requests.\n", __TASKNAME__);
if ((err = l4_receive(L4_ANYTHREAD)) < 0) {
printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__,
__FUNCTION__, err);
BUG();
}
/* Read conventional ipc data */
tag = l4_get_tag();
sender = l4_get_sender();
/* Read mrs not used by syslib */
for (int i = 0; i < MR_UNUSED_TOTAL; i++)
mr[i] = read_mr(i);
switch(tag) {
case L4_IPC_TAG_WAIT:
printf("%s: Synced with waiting thread.\n", __TASKNAME__);
break;
case L4_IPC_TAG_BLOCK_OPEN:
sys_open(sender, (void *)mr[0], (int)mr[1], (u32)mr[2]);
break;
default:
printf("%s: Unrecognised ipc tag (%d)"
"received. Ignoring.\n", __TASKNAME__, mr[MR_TAG]);
}
}
int main(void)
{
/* Initialise the block devices */
init_blkdev();
while (1) {
handle_block_device_request();
}
return 0;
}

View File

@@ -6,5 +6,6 @@
void init_blkdev(void)
{
ramdisk.ops.open(&ramdisk);
ramdisk[0].ops.init(&ramdisk[0]);
ramdisk[1].ops.init(&ramdisk[1]);
}

View File

@@ -1,7 +1,7 @@
/*
* A basic ramdisk implementation.
*
* Copyright (C) 2007 Bahadir Balban
* Copyright (C) 2007, 2008 Bahadir Balban
*
* The ramdisk binary is embedded in the data section of the ramdisk device
* executable. Read/writes simply occur to this area. The disk area could
@@ -22,45 +22,77 @@ extern char _end_ramdisk0[];
extern char _start_ramdisk1[];
extern char _end_ramdisk1[];
struct ramdisk_data {
u64 base;
u64 end;
};
struct ramdisk_data rddata[2];
__attribute__((section(".data.sfs"))) char sfsdisk[SZ_16MB];
static unsigned long ramdisk_base[2];
void ramdisk_open(struct block_device *ramdisk)
int ramdisk_init(struct block_device *ramdisk)
{
ramdisk_base = (unsigned long)_start_ramdisk;
ramdisk->size = (unsigned long)_end_ramdisk -
(unsigned long)_start_ramdisk;
struct ramdisk_data *rddata = ramdisk->private;
if (!strcmp("ramdisk0", ramdisk->name)) {
rddata->base = (u64)(unsigned long)_start_ramdisk0;
rddata->end = (u64)(unsigned long)_end_ramdisk0;
ramdisk->size = (u64)((unsigned long)_end_ramdisk0 -
(unsigned long)_start_ramdisk0);
} else if (!strcmp("ramdisk1", ramdisk->name)) {
rddata->base = (u64)(unsigned long)_start_ramdisk1;
rddata->end = (u64)(unsigned long)_end_ramdisk1;
ramdisk->size = (u64)((unsigned long)_end_ramdisk1 -
(unsigned long)_start_ramdisk1);
} else
return -1;
return 0;
}
void ramdisk_read(unsigned long offset, int size, void *buf)
int ramdisk_open(struct block_device *ramdisk)
{
void *src = (void *)(ramdisk_base + offset);
return 0;
}
int ramdisk_read(struct block_device *b, unsigned long offset, int size, void *buf)
{
struct ramdisk_data *data = b->private;
void *src = (void *)(unsigned long)(data->base + offset);
memcpy(buf, src, size);
return 0;
}
void ramdisk_write(unsigned long offset, int size, void *buf)
int ramdisk_write(struct block_device *b, unsigned long offset,
int size, void *buf)
{
void *dst = (void *)(ramdisk_base + offset);
struct ramdisk_data *data = b->private;
void *dst = (void *)(unsigned long)(data->base + offset);
memcpy(dst, buf, size);
return 0;
}
void ramdisk_readpage(unsigned long pfn, void *buf)
int ramdisk_readpage(struct block_device *b, unsigned long pfn, void *buf)
{
ramdisk_read(__pfn_to_addr(pfn), PAGE_SIZE, buf);
ramdisk_read(b, __pfn_to_addr(pfn), PAGE_SIZE, buf);
return 0;
}
void ramdisk_writepage(unsigned long pfn, void *buf)
int ramdisk_writepage(struct block_device *b, unsigned long pfn, void *buf)
{
ramdisk_write(__pfn_to_addr(pfn), PAGE_SIZE, buf);
ramdisk_write(b, __pfn_to_addr(pfn), PAGE_SIZE, buf);
return 0;
}
struct block_device ramdisk[2] = {
[0] = {
.name = "ramdisk0",
.private = &rddata[0],
.ops = {
.init = ramdisk_init,
.open = ramdisk_open,
.read = ramdisk_read,
.write = ramdisk_write,
@@ -70,7 +102,9 @@ struct block_device ramdisk[2] = {
},
[1] = {
.name = "ramdisk1",
.private = &rddata[1],
.ops = {
.init = ramdisk_init,
.open = ramdisk_open,
.read = ramdisk_read,
.write = ramdisk_write,

View File

@@ -14,12 +14,12 @@ tools_root = "../../tools"
kernel = join(project_root, "build/start.axf")
mm0 = join(project_root, "tasks/mm0/mm0.axf")
# fs0 = join(project_root, "tasks/fs0/fs0.axf")
fs0 = join(project_root, "tasks/fs0/fs0.axf")
test0 = join(project_root, "tasks/test0/test0.axf")
test1 = join(project_root, "tasks/test1/test1.axf")
#test1 = join(project_root, "tasks/test1/test1.axf")
#blkdev0 = join(project_root, "tasks/fsbin/blkdev0.axf")
images = [kernel, mm0, test0, test1]
images = [kernel, mm0, fs0, test0]
autogen_templ = "bootdesc.c.append"
def get_image_name_start_end(image, target):

View File

@@ -1,39 +0,0 @@
/* Supervisor task at load time. */
struct svc_image {
char name[16];
unsigned int phys_start;
unsigned int phys_end;
} __attribute__((__packed__));
/* Supervisor task descriptor at load time */
struct bootdesc {
int desc_size;
int total_images;
struct svc_image images[];
} __attribute__((__packed__));
struct bootdesc bootdesc = {
.desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * 3,
.total_images = 3,
.images = {
[0] = {
.name = "inittask",
.phys_start = 0x208000,
.phys_end = 0x213260,
},
[1] = {
.name = "roottask",
.phys_start = 0x218000,
.phys_end = 0x21b344,
},
[2] = {
.name = "testtask",
.phys_start = 0x220000,
.phys_end = 0x223344,
},
},
};

View File

@@ -14,7 +14,7 @@ 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/blkdev0/blkdev0.axf")
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"
@@ -26,6 +26,10 @@ 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")
@@ -47,16 +51,16 @@ 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],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path,\
"-L" + libmem_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', libc_name, \
'libl4'], # libgcc.a - This is required for division routines.
LIBS = [libc_name, 'gcc', 'libmc', 'libl4', 'gcc', libc_name],
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath])
CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath, libmem_incpath])
src = [glob("src/*.c"), glob("*.c"), glob("src/arch/arm/*.c")]
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)

8
tasks/fs0/include/bdev.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __BDEV_H__
#define __BDEV_H__
/*
* This is a mock-up compiled in blockdev buffer, to be used temporarily.
*/
void *vfs_rootdev_open(void);
#endif/* __BDEV_H__ */

18
tasks/fs0/include/file.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __FS0_MM_H__
#define __FS0_MM_H__
/*
* Describes the in-memory representation of a file. This is used to track
* file content, i.e. file pages by mm0, this is a temporary mock up until
* fs0 and mm0 are wired together.
*/
struct vm_file {
unsigned long vnum;
unsigned long length;
/* This is the cache of physical pages that this file has in memory. */
struct list_head page_cache_list;
struct vm_pager *pager;
};
#endif /* __FS0_MM_H__ */

View File

@@ -1,25 +1,41 @@
/*
* VFS definitions.
*
* Copyright (C) 2007 Bahadir Balban.
* Copyright (C) 2007, 2008 Bahadir Balban.
*/
#ifndef __FS_H__
#define __FS_H__
#include <l4/lib/list.h>
typedef void (*dentry_op_t)(void);
typedef void (*superblock_op_t)(void);
#include <l4/lib/list.h>
#include <l4/macros.h>
#include <l4lib/types.h>
#include <stat.h>
typedef void (*vnode_op_t)(void);
typedef void (*file_op_t)(void);
struct dentry;
struct file;
struct file_system_type;
struct superblock;
struct vnode;
struct dentry_ops {
dentry_op_t compare;
int (*compare)(struct dentry *d, char *n);
};
/* Operations that work on file content */
struct file_ops {
/* Read a vnode's contents by page range */
int (*read)(struct vnode *v, unsigned long pfn,
unsigned long npages, void *buf);
/* Write a vnode's contents by page range */
int (*write)(struct vnode *v, unsigned long pfn,
unsigned long npages, void *buf);
file_op_t open;
file_op_t read;
file_op_t write;
file_op_t close;
file_op_t mmap;
file_op_t lseek;
@@ -27,9 +43,11 @@ struct file_ops {
file_op_t fsync;
};
/* Operations that work on vnode fields and associations between vnodes */
struct vnode_ops {
vnode_op_t create;
vnode_op_t lookup;
struct vnode *(*lookup)(struct vnode *root, char *path);
void * (*readdir)(struct vnode *v, void *dirbuf);
vnode_op_t link;
vnode_op_t unlink;
vnode_op_t mkdir;
@@ -40,22 +58,28 @@ struct vnode_ops {
};
struct superblock_ops {
superblock_op_t read_sb;
superblock_op_t write_sb;
superblock_op_t read_vnode;
superblock_op_t write_vnode;
int (*write_sb)(struct superblock *sb);
/*
* Given a vnum, reads the disk-inode and copies its data
* into the vnode's generic fields
*/
int (*read_vnode)(struct superblock *sb, struct vnode *v);
/* Writes vnode's generic fields into the disk-inode structure */
int (*write_vnode)(struct superblock *sb, struct vnode *v);
/* Allocates a disk-inode along with a vnode, and associates the two */
struct vnode *(*alloc_vnode)(struct superblock *sb);
/* Frees the vnode and the corresponding on-disk inode */
int (*free_vnode)(struct superblock *sb, struct vnode *v);
};
struct dentry;
struct file;
struct file_system_type;
struct superblock;
struct vnode;
#define VFS_DENTRY_NAME_MAX 512
#define VFS_DNAME_MAX 256
struct dentry {
int refcnt;
char name[VFS_DENTRY_NAME_MAX];
char name[VFS_DNAME_MAX];
struct dentry *parent; /* Parent dentry */
struct list_head child; /* List of dentries with same parent */
struct list_head children; /* List of children dentries */
@@ -64,35 +88,54 @@ struct dentry {
struct dentry_ops ops;
};
struct file {
int refcnt;
struct dentry *dentry;
struct file_ops ops;
};
struct vnode {
unsigned long id; /* Filesystem-wide unique vnode id */
unsigned long vnum; /* Filesystem-wide unique vnode id */
int refcnt; /* Reference counter */
int hardlinks; /* Number of hard links */
struct superblock *sb; /* Reference to superblock */
struct vnode_ops ops; /* Operations on this vnode */
struct list_head dirents; /* Dirents that refer to this vnode */
struct file_ops fops; /* File-related operations on this vnode */
struct list_head dentries; /* Dirents that refer to this vnode */
struct list_head state_list; /* List for vnode's dirty/clean state */
unsigned long size; /* Total size of vnode in bytes */
u32 type; /* Vnode type, dev? socket? dir? ... */
u32 mode; /* Permissions */
u32 owner; /* Owner */
u64 atime; /* Last access time */
u64 mtime; /* Last content modification */
u64 ctime; /* Last vnode modification */
u64 size; /* Size of contents */
void *inode; /* Ptr to fs-specific inode */
};
struct file_system_type {
char name[256];
unsigned long magic;
unsigned int flags;
struct superblock *(*get_sb)(void);
struct list_head sb_list;
/* FS0 vfs specific macros */
#define vfs_isdir(v) S_ISDIR((v)->type)
struct fstype_ops {
struct superblock *(*get_superblock)(void *buf);
};
#define VFS_FSNAME_MAX 256
struct file_system_type {
char name[VFS_FSNAME_MAX];
unsigned long magic;
struct fstype_ops ops;
struct list_head list; /* Member of list of all fs types */
struct list_head sblist; /* List of superblocks with this type */
};
struct superblock *get_superblock(void *buf);
struct superblock {
struct file_system_type fs;
struct superblock_ops ops;
struct dentry *root_dirent;
u64 fssize;
unsigned int blocksize;
struct list_head list;
struct file_system_type *fs;
struct superblock_ops *ops;
struct vnode *root;
void *fs_super;
};
void vfs_mount_fs(struct superblock *sb);
extern struct dentry_ops generic_dentry_operations;
#endif /* __FS_H__ */

7
tasks/fs0/include/init.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef __INIT_H__
#define __INIT_H__
/* FS0 initialisation */
int initialise(void);
#endif /* __INIT_H__ */

View File

@@ -0,0 +1,19 @@
#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__ */

View File

@@ -4,13 +4,11 @@
#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_init(struct spinlock *s) { }
static inline void spin_lock(struct spinlock *s) { }
static inline void spin_unlock(struct spinlock *s) { }

View File

@@ -30,13 +30,13 @@ SECTIONS
/* 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)
.data : AT (ADDR(.data) - offset)
{
. = ALIGN(4K);
_start_ramdisk = .;
*(.data.diskspace)
_end_ramdisk = .;
*(.data)
_start_bdev = .;
*(.data.memfs)
_end_bdev = .;
*(.data)
}
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
_end = .;

View File

@@ -1,7 +0,0 @@
#ifndef __PRIVATE_MALLOC_H__
#define __PRIVATE_MALLOC_H__
void *kmalloc(size_t size);
void kfree(void *blk);
#endif /*__PRIVATE_MALLOC_H__ */

View File

@@ -0,0 +1,97 @@
/*
* The disk layout of our simple unix-like filesystem.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#ifndef __MEMFS_LAYOUT_H__
#define __MEMFS_LAYOUT_H__
#include <l4lib/types.h>
#include <l4/lib/list.h>
#include <l4/macros.h>
#include <l4/config.h>
#include INC_GLUE(memory.h)
#include <memcache/memcache.h>
#include <lib/idpool.h>
/*
*
* Filesystem layout:
*
* |---------------|
* | Superblock |
* |---------------|
*
* Superblock layout:
*
* |---------------|
* | inode cache |
* |---------------|
* | dentry cache |
* |---------------|
* | block cache |
* |---------------|
*
*/
/*
* These fixed filesystem limits make it much easier to implement
* filesystem space allocation.
*/
#define MEMFS_TOTAL_SIZE SZ_8MB
#define MEMFS_TOTAL_INODES 128
#define MEMFS_TOTAL_BLOCKS 2000
#define MEMFS_FMAX_BLOCKS 5
#define MEMFS_BLOCK_SIZE PAGE_SIZE
#define MEMFS_MAGIC 0xB
#define MEMFS_NAME "memfs"
#define MEMFS_NAME_SIZE 8
struct memfs_inode {
u32 inum; /* Inode number */
u32 mode; /* File permissions */
u32 owner; /* File owner */
u64 atime; /* Last access time */
u64 mtime; /* Last content modification */
u64 ctime; /* Last inode modification */
u64 size; /* Size of contents */
void *block[5]; /* Number of blocks */
};
struct memfs_superblock {
u32 magic; /* Filesystem magic number */
char name[8];
u32 blocksize; /* Filesystem block size */
u64 fmaxblocks; /* Maximum number of blocks per file */
u64 fssize; /* Total size of filesystem */
struct memfs_inode *root; /* The root of this superblock */
struct list_head inode_cache_list; /* Chain of alloc caches */
struct list_head block_cache_list; /* Chain of alloc caches */
struct id_pool *ipool; /* Index pool for inodes */
struct id_pool *bpool; /* Index pool for blocks */
struct memfs_inode *inode[MEMFS_TOTAL_INODES]; /* Table of inodes */
void *block[MEMFS_TOTAL_BLOCKS]; /* Table of fs blocks */
} __attribute__ ((__packed__));
#define MEMFS_DNAME_MAX 32
struct memfs_dentry {
u32 inum; /* Inode number */
u32 nlength; /* Name length */
u8 name[MEMFS_DNAME_MAX]; /* Name string */
};
extern struct vnode_ops memfs_vnode_operations;
extern struct superblock_ops memfs_superblock_operations;
extern struct file_ops memfs_file_operations;
extern struct memfs_superblock *memfs_superblock;
int memfs_format_filesystem(void *buffer);
struct memfs_inode *memfs_create_inode(struct memfs_superblock *sb);
void memfs_register_fstype(struct list_head *);
struct superblock *memfs_get_superblock(void *block);
int memfs_generate_superblock(void *block);
void *memfs_alloc_block(struct memfs_superblock *sb);
int memfs_free_block(struct memfs_superblock *sb, void *block);
#endif /* __MEMFS_LAYOUT_H__ */

View File

@@ -0,0 +1,7 @@
#ifndef __MEMFS_VNODE_H__
#define __MEMFS_VNODE_H__
#include <fs.h>
#endif /* __MEMFS_VNODE_H__ */

View File

@@ -1,7 +1,25 @@
/*
* Copyright (C) 2008 Bahadir Balban
*/
#ifndef __FS0_TASK_H__
#define __FS0_TASK_H__
#include <lib/idpool.h>
#include <l4/lib/list.h>
#define __TASKNAME__ "FS0"
#endif /* __FS0_TASK_H__ */
#define TASK_OFILES_MAX 32
/* Thread control block, fs0 portion */
struct tcb {
l4id_t tid;
struct list_head list;
int fd[TASK_OFILES_MAX];
struct id_pool *fdpool;
};
struct tcb *find_task(int tid);
void init_task_data(void);
#endif /* __FS0_TASK_H__ */

14
tasks/fs0/src/bdev.c Normal file
View File

@@ -0,0 +1,14 @@
/*
* This is just to allocate some memory as a block device.
*/
#include <l4/macros.h>
extern char _start_bdev[];
extern char _end_bdev[];
__attribute__((section(".data.memfs"))) char blockdevice[SZ_16MB];
void *vfs_rootdev_open(void)
{
return (void *)_start_bdev;
}

29
tasks/fs0/src/c0fs/c0fs.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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 list_head *fslist)
{
list_add(&sfs_type.list, fslist);
}

View File

@@ -4,10 +4,11 @@
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#ifndef __SFS_LAYOUT_H__
#define __SFS_LAYOUT_H__
#ifndef __C0FS_LAYOUT_H__
#define __C0FS_LAYOUT_H__
#include <l4lib/types.h>
#include <l4/lib/list.h>
#include <l4/macros.h>
#include <l4/config.h>
#include INC_GLUE(memory.h)
@@ -54,13 +55,20 @@
struct sfs_superblock {
u32 magic; /* Filesystem magic number */
u32 fssize; /* Total size of filesystem */
u32 szidx; /* Bitmap index size */
u64 fssize; /* Total size of filesystem */
u32 total; /* To */
u32 groupmap[]; /* Bitmap of all fs groups */
};
struct sfs_group_table {
u32 total;
u32 free;
u32 groupmap[];
};
struct sfs_inode_table {
u32 szidx;
u32 total;
u32 free;
u32 inodemap[INODE_BITMAP_SIZE];
struct sfs_inode inode[INODE_TABLE_SIZE];
};
@@ -74,7 +82,7 @@ struct sfs_inode_table {
*/
#define INODE_DIRECT_BLOCKS 5
struct sfs_inode_blocks {
u32 szidx; /* Direct array index size */
int szidx; /* Direct array index size */
unsigned long indirect;
unsigned long indirect2;
unsigned long indirect3;
@@ -86,10 +94,10 @@ struct sfs_inode {
u32 inum; /* Inode number */
u32 mode; /* File permissions */
u32 owner; /* File owner */
u32 atime; /* Last access time */
u32 mtime; /* Last content modification */
u32 ctime; /* Last inode modification */
u32 size; /* Size of contents */
u64 atime; /* Last access time */
u64 mtime; /* Last content modification */
u64 ctime; /* Last inode modification */
u64 size; /* Size of contents */
struct sfs_inode_blocks blocks;
} __attribute__ ((__packed__));
@@ -99,4 +107,7 @@ struct sfs_dentry {
u8 name[]; /* Name string */
} __attribute__ ((__packed__));
#endif /* __SFS_LAYOUT_H__ */
void sfs_register_type(struct list_head *);
#endif /* __C0FS_LAYOUT_H__ */

28
tasks/fs0/src/file.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* File content tracking.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <fs.h>
#include <file.h>
#include <l4/lib/list.h>
#include <l4/macros.h>
#include INC_GLUE(memory.h)
#include <stdio.h>
/* List of all in-memory files. */
struct list_head vm_file_list;
/*
* This reads contents of a file in pages, calling the fs-specific file read function to read-in
* those pages' contents.
*
* Normally this is ought to be called by mm0 when a file's pages cannot be found in the page
* cache.
*/
int generic_file_read(struct vnode *v, unsigned long pfn, unsigned long npages, void *page_buf)
{
BUG_ON(!is_page_aligned(page_buf));
return v->fops.read(v, pfn, npages, page_buf);
}

View File

@@ -3,19 +3,92 @@
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <kdata.h>
#include <fs.h>
#include <string.h>
#include <vfs.h>
#include <bdev.h>
#include <task.h>
#include <kdata.h>
#include <stdio.h>
#include <string.h>
#include <l4/lib/list.h>
#include <init.h>
#include <blkdev/blkdev.h>
#include <l4/api/errno.h>
#include <memfs/memfs.h>
void initialise(void)
struct list_head fs_type_list;
struct superblock *vfs_probe_filesystems(void *block)
{
struct block_device *bdev;
struct file_system_type *fstype;
struct superblock *sb;
request_initdata(&initdata);
vfs_probe_fs(bdev);
list_for_each_entry(fstype, &fs_type_list, list) {
/* Does the superblock match for this fs type? */
if ((sb = fstype->ops.get_superblock(block))) {
/*
* Add this to the list of superblocks this
* fs already has.
*/
list_add(&sb->list, &fstype->sblist);
return sb;
}
}
return PTR_ERR(-ENODEV);
}
/*
* Registers each available filesystem so that these can be
* used when probing superblocks on block devices.
*/
void vfs_register_filesystems(void)
{
/* Initialise fstype list */
INIT_LIST_HEAD(&fs_type_list);
/* Call per-fs registration functions */
memfs_register_fstype(&fs_type_list);
}
extern struct list_head vm_file_list;
/*
* Filesystem initialisation.
*/
int initialise(void)
{
void *rootdev_blocks;
struct superblock *root_sb;
/* Get standard init data from microkernel */
request_initdata(&initdata);
/* Register compiled-in filesystems with vfs core. */
vfs_register_filesystems();
/* Get a pointer to first block of root block device */
rootdev_blocks = vfs_rootdev_open();
/*
* Since the *only* filesystem we have is a temporary memory
* filesystem, we create it on the root device first.
*/
memfs_format_filesystem(rootdev_blocks);
INIT_LIST_HEAD(&vm_file_list);
/* Search for a filesystem on the root device */
BUG_ON(IS_ERR(root_sb = vfs_probe_filesystems(rootdev_blocks)));
/* Mount the filesystem on the root device */
vfs_mount_root(root_sb);
/* Learn about what tasks are running */
init_task_data();
/*
* Initialisation is done. From here on, we can start
* serving filesystem requests.
*/
return 0;
}

View File

@@ -4,7 +4,9 @@
* Copyright (C) 2007 Bahadir Balban
*/
#include <lib/idpool.h>
#include <kmalloc/kmalloc.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>

View File

@@ -42,7 +42,7 @@ typedef struct _malloc /* Turbo C DJGPP */
static char *g_heap_bot, *g_kbrk, *g_heap_top;
/*****************************************************************************
*****************************************************************************/
static void dump_heap(void)
void dump_heap(void)
{
unsigned blks_used = 0, blks_free = 0;
size_t bytes_used = 0, bytes_free = 0;
@@ -204,6 +204,15 @@ create a new, free block */
}
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)

111
tasks/fs0/src/lookup.c Normal file
View File

@@ -0,0 +1,111 @@
/*
* Inode lookup.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#include <fs.h>
#include <vfs.h>
#include <stat.h>
#include <l4/api/errno.h>
/*
* Splits the string str according to the given seperator, returns the
* first component, and modifies the str so that it points at the next
* available component (or a leading separator which can be filtered
* out on a subsequent call to this function).
*/
char *splitpath(char **str, char sep)
{
char *cursor = *str;
char *end;
/* Move forward until no seperator */
while (*cursor == sep) {
*cursor = '\0';
cursor++; /* Move to first char of component */
}
end = cursor;
while (*end != sep && *end != '\0')
end++; /* Move until end of component */
if (*end == sep) { /* if ended with separator */
*end = '\0'; /* finish component by null */
if (*(end + 1) != '\0') /* if more components after, */
*str = end + 1; /* assign beginning to str */
else
*str = end; /* else str is also depleted, give null */
} else /* if end was null, that means the end for str, too. */
*str = end;
return cursor;
}
/*
* Given a dentry that has been populated by readdir with children dentries
* and their vnodes, this itself checks all those children on that level for
* a match, but it also calls lookup, which recursively checks lower levels.
*/
struct vnode *lookup_dentry_children(struct dentry *parentdir, char *path)
{
struct dentry *childdir;
struct vnode *v;
list_for_each_entry(childdir, &parentdir->children, child)
/* Non-zero result means either found it or error occured */
if ((v = childdir->vnode->ops.lookup(childdir->vnode, path)))
return v;
/* Out of all children dentries, neither was a match, so we return 0 */
return 0;
}
/* Lookup, recursive, assuming single-mountpoint */
struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path)
{
char *component = splitpath(&path, VFS_STR_SEP);
struct dentry *d;
struct vnode *found;
int err;
/* Does this path component match with any of parent vnode's names? */
list_for_each_entry(d, &thisnode->dentries, vref) {
if (d->ops.compare(d, component)) {
/* Is this a directory? */
if (vfs_isdir(thisnode)) {
/* Are there any more path components? */
if (path)
/* Read directory contents */
if (IS_ERR(err = (int)d->vnode->ops.readdir(d->vnode, 0)))
return PTR_ERR(err);
/* Search all children one level below. */
if ((found = lookup_dentry_children(d, path)))
/* Either found, or non-zero error */
return found;
else
return thisnode;
} else { /* Its a file */
if (path) /* There's still path, but not directory */
return PTR_ERR(-ENOTDIR);
else /* No path left, found it, so return file */
return thisnode;
}
}
}
/* Not found, return nothing */
return 0;
}
int generic_dentry_compare(struct dentry *d, char *name)
{
if (!strcmp(d->name, name))
return 1;
else
return 0;
}
struct dentry_ops generic_dentry_operations = {
.compare = generic_dentry_compare,
};

136
tasks/fs0/src/memfs/file.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* Memfs file operations
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <fs.h>
#include <vfs.h>
#include <file.h>
#include <memfs/memfs.h>
#include <stdio.h>
#include <string.h>
#include <l4/macros.h>
#include <l4/api/errno.h>
#include INC_GLUE(memory.h)
#if 0
/*
* FIXME: read_write() could be more layered using these functions.
*/
void *memfs_read_block(struct vnode *v, int blknum)
{
void *buf = vfs_alloc_block();
if (!buf)
return PTR_ERR(-ENOMEM);
if(!v->block[blknum])
return PTR_ERR(-EEXIST);
memcpy(buf, &v->block[blknum], v->sb->blocksize);
return buf;
}
int memfs_write_block(struct vnode *v, int blknum, void *buf)
{
if(!v->block[blknum])
return -EEXIST;
memcpy(&v->block[blknum], buf, v->sb->blocksize);
return 0;
}
#endif
/*
* Handles both read and writes since most details are common.
*/
int memfs_file_read_write(struct vnode *v, unsigned long pfn,
unsigned long npages, void *buf, int wr)
{
struct memfs_inode *i;
struct memfs_superblock *memfs_sb;
u32 blocksize;
/* Don't support different block and page sizes for now */
BUG_ON(v->sb->blocksize != PAGE_SIZE);
/* Buffer must be page aligned */
BUG_ON(!is_page_aligned(buf));
/* Low-level fs refs must be valid */
BUG_ON(!(i = v->inode));
BUG_ON(!(memfs_sb = v->sb->fs_super));
blocksize = v->sb->blocksize;
/* Check filesystem per-file size limit */
if ((pfn + npages) > memfs_sb->fmaxblocks) {
printf("%s: fslimit: Trying to %s outside maximum file range: %x-%x\n",
__FUNCTION__, (wr) ? "write" : "read", pfn, pfn + npages);
return -EINVAL; /* Same error that posix llseek returns */
}
/* Read-specific operations */
if (!wr) {
/* Check if read is beyond EOF */
if ((pfn + npages) > __pfn(v->size)) {
printf("%s: Trying to read beyond end of file: %x-%x\n",
__FUNCTION__, pfn, pfn + npages);
return -EINVAL; /* Same error that posix llseek returns */
}
/* Copy the data from inode blocks into page buffer */
for (int x = pfn, bufpage = 0; x < pfn + npages; x++, bufpage++)
memcpy(((void *)buf) + (bufpage * blocksize),
&i->block[x], blocksize);
} else { /* Write-specific operations */
/* Is the write beyond current file size? */
if (i->size < ((pfn + npages) * (blocksize))) {
unsigned long diff = pfn + npages - __pfn(i->size);
unsigned long holes;
/*
* If write is not consecutively after the currently
* last file block, the gap must be filled in by holes.
*/
if (pfn > __pfn(i->size))
holes = pfn - __pfn(i->size);
/* Allocate new blocks */
for (int x = 0; x < diff; x++)
if (!(i->block[__pfn(i->size) + x] = memfs_alloc_block(memfs_sb)))
return -ENOSPC;
/* Zero out the holes. FIXME: How do we zero out non-page-aligned bytes?` */
for (int x = 0; x < holes; x++)
memset(i->block[__pfn(i->size) + x], 0, blocksize);
/* Update size and the vnode. FIXME: How do we handle non page-aligned size */
i->size = (pfn + npages) * blocksize;
v->sb->ops->read_vnode(v->sb, v);
}
/* Copy the data from page buffer into inode blocks */
for (int x = pfn, bufpage = 0; x < pfn + npages; x++, bufpage++)
memcpy(i->block[x], ((void *)buf) + (bufpage * blocksize), blocksize);
}
return npages * blocksize;
}
int memfs_file_write(struct vnode *v, unsigned long pfn, unsigned long npages, void *buf)
{
return memfs_file_read_write(v, pfn, npages, buf, 1);
}
int memfs_file_read(struct vnode *v, unsigned long pfn, unsigned long npages, void *buf)
{
return memfs_file_read_write(v, pfn, npages, buf, 0);
}
struct file_ops memfs_file_operations = {
.read = memfs_file_read,
.write = memfs_file_write,
};

159
tasks/fs0/src/memfs/memfs.c Normal file
View File

@@ -0,0 +1,159 @@
/*
* A simple read/writeable memory-only filesystem.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#include <init.h>
#include <fs.h>
#include <vfs.h>
#include <memfs/memfs.h>
#include <memfs/vnode.h>
#include <lib/idpool.h>
#include <l4/macros.h>
#include <l4/types.h>
#include <l4/api/errno.h>
#include INC_GLUE(memory.h)
struct memfs_superblock *memfs_superblock;
/* Initialise allocation caches as part of superblock initialisation */
int memfs_init_caches(struct memfs_superblock *sb)
{
void *free_block;
struct mem_cache *block_cache;
struct mem_cache *inode_cache;
/* Use the whole filesystem space to initialise block cache */
free_block = (void *)sb + sizeof(*sb);
block_cache = mem_cache_init(free_block, sb->fssize - sizeof(*sb),
sb->blocksize, 1);
list_add(&block_cache->list, &sb->block_cache_list);
/* Allocate a block and initialise it as first inode cache */
free_block = mem_cache_alloc(block_cache);
inode_cache = mem_cache_init(free_block, sb->blocksize,
sizeof(struct memfs_inode), 0);
list_add(&inode_cache->list, &sb->inode_cache_list);
return 0;
}
/*
* Given an empty block buffer, initialises a filesystem there.
*/
int memfs_format_filesystem(void *buffer)
{
struct memfs_superblock *sb = buffer; /* Buffer is the first block */
/* Zero initialise the superblock area */
memset(sb, 0, sizeof(*sb));
/* Initialise filesystem parameters */
sb->magic = MEMFS_MAGIC;
memcpy(sb->name, MEMFS_NAME, MEMFS_NAME_SIZE);
sb->blocksize = MEMFS_BLOCK_SIZE;
sb->fmaxblocks = MEMFS_FMAX_BLOCKS;
sb->fssize = MEMFS_TOTAL_SIZE;
/* Initialise block and inode index pools */
sb->ipool = id_pool_new_init(MEMFS_TOTAL_INODES);
sb->bpool = id_pool_new_init(MEMFS_TOTAL_BLOCKS);
/* Initialise bitmap allocation lists for blocks and inodes */
INIT_LIST_HEAD(&sb->block_cache_list);
INIT_LIST_HEAD(&sb->inode_cache_list);
memfs_init_caches(sb);
/* We allocate and fix a root inode so the sb is ready for mount */
sb->root = memfs_create_inode(sb);
return 0;
}
/* Allocates a block of unused buffer */
void *memfs_alloc_block(struct memfs_superblock *sb)
{
struct mem_cache *cache;
list_for_each_entry(cache, &sb->block_cache_list, list) {
if (cache->free)
return mem_cache_zalloc(cache);
else
continue;
}
return PTR_ERR(-ENOSPC);
}
/*
* Even though on a list, block allocation is currently from a single cache.
* This frees a block back to the free buffer cache.
*/
int memfs_free_block(struct memfs_superblock *sb, void *block)
{
struct mem_cache *c, *tmp;
list_for_each_entry_safe(c, tmp, &sb->block_cache_list, list)
if (!mem_cache_free(c, block))
return 0;
else
return -EINVAL;
return -EINVAL;
}
struct superblock *memfs_get_superblock(void *block);
struct file_system_type memfs_fstype = {
.name = "memfs",
.magic = MEMFS_MAGIC,
.ops = {
.get_superblock = memfs_get_superblock,
},
};
/* Copies fs-specific superblock into generic vfs superblock */
struct superblock *memfs_fill_superblock(struct memfs_superblock *sb,
struct superblock *vfs_sb)
{
vfs_sb->fs = &memfs_fstype;
vfs_sb->ops = &memfs_superblock_operations;
vfs_sb->fs_super = sb;
vfs_sb->fssize = sb->fssize;
vfs_sb->blocksize = sb->blocksize;
/*
* Create the first vnode. Since this is memfs, root vnode is
* not read-in but dynamically created here.
*/
vfs_sb->ops->alloc_vnode(vfs_sb);
return vfs_sb;
}
/*
* Probes block buffer for a valid memfs superblock, if found,
* allocates and copies data to a vfs superblock, and returns it.
*/
struct superblock *memfs_get_superblock(void *block)
{
struct memfs_superblock *sb = block;
struct superblock *vfs_sb;
/* We don't do sanity checks here, just confirm id. */
if (!strcmp(sb->name, "memfs"))
return 0;
if (sb->magic != MEMFS_MAGIC)
return 0;
/* Allocate a vfs superblock. */
vfs_sb = vfs_alloc_superblock();
/* Fill generic sb from fs-specific sb */
return memfs_fill_superblock(sb, vfs_sb);
}
/* Registers sfs as an available filesystem type */
void memfs_register_fstype(struct list_head *fslist)
{
list_add(&memfs_fstype.list, fslist);
}

278
tasks/fs0/src/memfs/vnode.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* Inode and vnode implementation.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <fs.h>
#include <vfs.h>
#include <memfs/memfs.h>
#include <memfs/file.h>
#include <l4/lib/list.h>
#include <l4/api/errno.h>
#include <l4/macros.h>
#include <lib/malloc.h>
#include <stdio.h>
struct memfs_inode *memfs_alloc_inode(struct memfs_superblock *sb)
{
struct mem_cache *cache;
struct memfs_inode *i;
void *free_block;
/* Ask existing inode caches for a new inode */
list_for_each_entry(cache, &sb->inode_cache_list, list) {
if (cache->free)
if (!(i = mem_cache_zalloc(cache)))
return PTR_ERR(-ENOSPC);
else
return i;
else
continue;
}
/* Ask existing block caches for a new block */
if (IS_ERR(free_block = memfs_alloc_block(sb)))
return PTR_ERR(free_block);
/* Initialise it as an inode cache */
cache = mem_cache_init(free_block, sb->blocksize,
sizeof(struct memfs_inode), 0);
list_add(&cache->list, &sb->inode_cache_list);
if (!(i = mem_cache_zalloc(cache)))
return PTR_ERR(-ENOSPC);
else
return i;
}
/*
* O(n^2) complexity but its simple, yet it would only reveal on high numbers.
*/
int memfs_free_inode(struct memfs_superblock *sb, struct memfs_inode *i)
{
struct mem_cache *c, *tmp;
list_for_each_entry_safe(c, tmp, &sb->inode_cache_list, list) {
/* Free it, if success */
if (!mem_cache_free(c, i)) {
/* If cache completely emtpy */
if (mem_cache_is_empty(c)) {
/* Free the block, too. */
list_del(&c->list);
memfs_free_block(sb, c);
}
return 0;
}
}
return -EINVAL;
}
/* Allocates *and* initialises the inode */
struct memfs_inode *memfs_create_inode(struct memfs_superblock *sb)
{
struct memfs_inode *i;
/* Allocate the inode */
if (PTR_ERR(i = memfs_alloc_inode(sb)) < 0)
return i;
/* Allocate a new inode number */
if ((i->inum = id_new(sb->ipool)) < 0)
return i;
/* Put a reference to this inode in the inode table at this index */
sb->inode[i->inum] = i;
return i;
}
/* Deallocate the inode and any other closely relevant structure */
int memfs_destroy_inode(struct memfs_superblock *sb, struct memfs_inode *i)
{
int inum = i->inum;
/* Deallocate the inode */
if (memfs_free_inode(sb, i) < 0)
return -EINVAL;
/* Deallocate the inode number */
if (id_del(sb->ipool, inum) < 0)
return -EINVAL;
/* Clear the ref in inode table */
sb->inode[inum] = 0;
return 0;
}
struct vnode *memfs_alloc_vnode(struct superblock *sb)
{
struct memfs_inode *i;
struct vnode *v;
/* Get a (pseudo-disk) memfs inode */
if (IS_ERR(i = memfs_create_inode(sb->fs_super)))
return PTR_ERR(i);
/* Get a vnode */
if (!(v = vfs_alloc_vnode()))
return PTR_ERR(-ENOMEM);
/* Associate the two together */
v->inode = i;
v->vnum = i->inum;
/* Associate memfs-specific fields with vnode */
v->ops = memfs_vnode_operations;
v->fops = memfs_file_operations;
/* Return the vnode */
return v;
}
int memfs_free_vnode(struct superblock *sb, struct vnode *v)
{
struct memfs_inode *i = v->inode;
BUG_ON(!i); /* Vnodes that come here must have valid inodes */
/* Destroy on-disk inode */
memfs_destroy_inode(sb->fs_super, i);
/* Free vnode */
vfs_free_vnode(v);
return 0;
}
/*
* Given a vnode with a valid vnum, this retrieves the corresponding
* inode from the filesystem.
*/
struct memfs_inode *memfs_read_inode(struct superblock *sb, struct vnode *v)
{
struct memfs_superblock *fssb = sb->fs_super;
BUG_ON(!fssb->inode[v->vnum]);
return fssb->inode[v->vnum];
}
/*
* Given a preallocated vnode with a valid vnum, this reads the corresponding
* inode from the filesystem and fills in the vnode's fields.
*/
int memfs_read_vnode(struct superblock *sb, struct vnode *v)
{
struct memfs_inode *i = memfs_read_inode(sb, v);
if (!i)
return -EEXIST;
/* Simply copy common fields */
v->vnum = i->inum;
v->size = i->size;
v->mode = i->mode;
v->owner = i->owner;
v->atime = i->atime;
v->mtime = i->mtime;
v->ctime = i->ctime;
return 0;
}
int memfs_write_vnode(struct superblock *sb, struct vnode *v)
{
struct memfs_inode *i = v->inode;
/* Vnodes that come here must have valid inodes */
BUG_ON(!i);
/* Simply copy common fields */
i->inum = v->vnum;
i->size = v->size;
i->mode = v->mode;
i->owner = v->owner;
i->atime = v->atime;
i->mtime = v->mtime;
i->ctime = v->ctime;
return 0;
}
/*
* Allocates and populates all dentries and their corresponding vnodes that are
* the direct children of vnode v. This means that by each call to readdir, the vfs
* layer increases its cache of filesystem tree by one level beneath that directory.
*/
void *memfs_vnode_readdir(struct vnode *v, void *dirbuf)
{
int err;
struct memfs_dentry *memfsd = dirbuf;
struct dentry *parent = list_entry(v->dentries.next, struct dentry,
vref);
/* Check directory type */
if (!vfs_isdir(v))
return PTR_ERR(-ENOTDIR);
/* Allocate dirbuf if one is not provided by the upper layer */
if (!dirbuf) {
/* This is as big as a page */
memfsd = dirbuf = vfs_alloc_dirpage();
/*
* Fail if vnode size is bigger than a page. Since this allocation
* method is to be replaced, we can live with this limitation for now.
*/
BUG_ON(v->size > PAGE_SIZE);
}
/* Read contents into the buffer */
if ((err = v->fops.read(v, 0, 1, dirbuf)))
return PTR_ERR(err);
/* For each fs-specific directory entry */
for (int i = 0; i < (v->size / sizeof(struct memfs_dentry)); i++) {
struct dentry *newd;
struct vnode *newv;
/* Allocate a vfs dentry */
if (!(newd = vfs_alloc_dentry()))
return PTR_ERR(-ENOMEM);
/* Initialise it */
newd->ops = generic_dentry_operations;
newd->parent = parent;
list_add(&newd->child, &parent->children);
/*
* Read the vnode for dentry by its vnode number.
*/
newv = newd->vnode = vfs_alloc_vnode();
newv->vnum = memfsd[i].inum;
BUG_ON(newv->sb->ops->read_vnode(newv->sb, newv) < 0);
/* Assing this dentry as a name of its vnode */
list_add(&newd->vref, &newd->vnode->dentries);
/* Copy fields into generic dentry */
memcpy(newd->name, memfsd[i].name, MEMFS_DNAME_MAX);
}
return dirbuf;
}
struct vnode_ops memfs_vnode_operations = {
.lookup = generic_vnode_lookup,
.readdir = memfs_vnode_readdir,
};
struct superblock_ops memfs_superblock_operations = {
.read_vnode = memfs_read_vnode,
.write_vnode = memfs_write_vnode,
.alloc_vnode = memfs_alloc_vnode,
.free_vnode = memfs_free_vnode,
};

View File

View File

@@ -1,17 +0,0 @@
/*
* A basic unix-like read/writeable filesystem.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
void sfs_read_sb(struct superblock *sb)
{
}
static void simplefs_alloc_vnode(struct vnode *)
{
}

95
tasks/fs0/src/syscalls.c Normal file
View File

@@ -0,0 +1,95 @@
/*
* 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 <vfs.h>
#include <lib/malloc.h>
#include <string.h>
#include <stdio.h>
#include <task.h>
/*
* This notifies mm0 that this is the fd that refers to this vnode number
* from now on.
*
* 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.
*/
int send_pager_opendata(l4id_t sender, int fd, unsigned long vnum)
{
int err;
write_mr(L4SYS_ARG0, sender);
write_mr(L4SYS_ARG1, fd);
write_mr(L4SYS_ARG2, vnum);
if ((err = l4_send(PAGER_TID, L4_IPC_TAG_OPENDATA)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
return err;
}
return 0;
}
int do_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
{
struct vnode *v;
struct tcb *t;
int fd;
/* FIXME: Use strnlen */
char *pathcopy = kmalloc(strlen(pathname));
/* FIXME: Use strncpy */
memcpy(pathcopy, pathname, strlen(pathname));
/* Get the vnode */
if (IS_ERR(v = vfs_lookup(vfs_root.pivot->sb, pathcopy)))
return (int)v;
/* Get the task */
BUG_ON(!(t = find_task(sender)));
/* Get a new fd */
BUG_ON(!(fd = id_new(t->fdpool)));
/* Assign the new fd with the vnode's number */
t->fd[fd] = v->vnum;
/* Tell mm0 about opened vnode information */
BUG_ON(send_pager_opendata(sender, fd, v->vnum) < 0);
return 0;
}
/* FIXME:
* - Is it already open?
* - Allocate a copy of path string since lookup destroys it
* - Check flags and mode.
*/
int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
{
return do_open(sender, pathname, flags, mode);
}
int sys_read(l4id_t sender, int fd, void *buf, int count)
{
return 0;
}
int sys_write(l4id_t sender, int fd, const void *buf, int count)
{
return 0;
}
int sys_lseek(l4id_t sender, int fd, int offset, int whence)
{
return 0;
}

107
tasks/fs0/src/task.c Normal file
View File

@@ -0,0 +1,107 @@
/*
* 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/ipcdefs.h>
#include <lib/malloc.h>
#include <task.h>
struct tcb_head {
struct list_head list;
int total; /* Total threads */
} tcb_head;
struct tcb *find_task(int tid)
{
struct tcb *t;
list_for_each_entry(t, &tcb_head.list, list)
if (t->tid == tid)
return t;
return 0;
}
/*
* Asks pager to send information about currently running tasks. Since this is
* called during initialisation, there can't be that many, so we assume message
* registers are sufficient. First argument tells how many there are, the rest
* tells the tids.
*/
int receive_pager_taskdata(l4id_t *tdata)
{
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 err;
}
/* Check if call itself was successful */
if ((err = l4_get_retval()) < 0) {
printf("%s: Error: %d.\n", __FUNCTION__, err);
return err;
}
/* Read total number of tasks. Note already used one mr. */
if ((tdata[0] = (l4id_t)read_mr(L4SYS_ARG0)) >= MR_UNUSED_TOTAL) {
printf("%s: Error: Too many tasks to read. Won't fit in mrs.\n",
__FUNCTION__);
BUG();
}
/* Now read task ids. */
for (int i = 0; i < (int)tdata[0]; i++)
tdata[1 + i] = (l4id_t)read_mr(L4SYS_ARG1 + i);
return 0;
}
/* Allocate a task struct and initialise it */
struct tcb *create_tcb(l4id_t tid)
{
struct tcb *t;
if (!(t = kmalloc(sizeof(*t))))
return PTR_ERR(-ENOMEM);
t->tid = tid;
INIT_LIST_HEAD(&t->list);
list_add_tail(&t->list, &tcb_head.list);
tcb_head.total++;
return t;
}
int init_task_structs(l4id_t *tdata)
{
struct tcb *t;
int total = tdata[0];
for (int i = 0; i < total; i++)
if (IS_ERR(t = create_tcb(tdata[1 + i])))
return (int)t;
return 0;
}
void init_task_data(void)
{
l4id_t tdata[MR_UNUSED_TOTAL];
INIT_LIST_HEAD(&tcb_head.list);
/* Read how many tasks and tids of each */
BUG_ON(receive_pager_taskdata(tdata) < 0);
/* Initialise local task structs using this info */
init_task_structs(tdata);
}

36
tasks/fs0/src/vfs.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* High-level vfs implementation.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <fs.h>
#include <vfs.h>
struct vnode *vfs_lookup(struct superblock *sb, char *path)
{
/* If it's just / we already got it. */
if (!strcmp(path, "/"))
return sb->root;
return sb->root->ops.lookup(sb->root, path);
}
/*
* /
* /boot
* /boot/images/mm0.axf
* /boot/images/fs0.axf
* /boot/images/test0.axf
* /file.txt
*/
struct vfs_mountpoint vfs_root;
int vfs_mount_root(struct superblock *sb)
{
/* Lookup the root vnode of this superblock */
vfs_root.pivot = vfs_lookup(sb, "/");
vfs_root.sb = sb;
return 0;
}

View File

@@ -91,14 +91,14 @@ static inline void l4_set_retval(int retval)
/* Clients:
* Learn result of request.
*/
*/
static inline int l4_get_retval(void)
{
return read_mr(MR_RETURN);
}
/* Servers:
* Return the ipc result back to requesting task.
* Return the ipc result back to requesting task.
*/
static inline int l4_ipc_return(int retval)
{
@@ -175,5 +175,4 @@ static inline int l4_reclaim_pages(l4id_t tid)
return 0;
}
#endif /* __L4LIB_SYSLIB_H__ */

View File

@@ -22,6 +22,7 @@
#define MR_UNUSED_START 2 /* The first mr that's not used by syslib.h */
#define MR_TOTAL 6
#define MR_UNUSED_TOTAL (MR_TOTAL - MR_UNUSED_START)
#define MR_USABLE_TOTAL MR_UNUSED_TOTAL
/* Compact utcb for now! :-) */
struct utcb {

View File

@@ -40,4 +40,8 @@
#define L4_IPC_TAG_CLOSE 16
#define L4_IPC_TAG_BRK 17
/* Tags for ipc between fs0 and mm0 */
#define L4_IPC_TAG_OPENDATA 25
#define L4_IPC_TAG_TASKDATA 26
#endif /* __IPCDEFS_H__ */

View File

@@ -2,7 +2,7 @@
* This is the glue logic between posix shared memory functions
* and their L4 implementation.
*
* Copyright (C) 2007 Bahadir Balban
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#include <errno.h>
#include <stdio.h>
@@ -12,80 +12,110 @@
#include <l4lib/arch/syslib.h>
#include <l4lib/ipcdefs.h>
#define PTR_ERR(x) ((void *)(x))
#define IS_ERR(x) (((int)(x)) < 0)
static inline int l4_shmget(l4id_t key, int size, int shmflg)
int l4_shmget(l4id_t key, int size, int shmflg)
{
int err;
write_mr(L4SYS_ARG0, key);
write_mr(L4SYS_ARG1, size);
write_mr(L4SYS_ARG2, shmflg);
/* Call pager with shmget() request. Check ipc error. */
if ((errno = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMGET)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, errno);
return -1;
if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMGET)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
return err;
}
/* Check if syscall itself was successful */
if ((errno = l4_get_retval()) < 0) {
printf("%s: SHMGET Error: %d.\n", __FUNCTION__, errno);
return -1;
if ((err = l4_get_retval()) < 0) {
printf("%s: SHMGET Error: %d.\n", __FUNCTION__, err);
return err;
}
/* Obtain shmid. */
return read_mr(L4SYS_ARG0);
}
static inline void *l4_shmat(l4id_t shmid, const void *shmaddr, int shmflg)
void *l4_shmat(l4id_t shmid, const void *shmaddr, int shmflg)
{
int err;
write_mr(L4SYS_ARG0, shmid);
write_mr(L4SYS_ARG1, (unsigned long)shmaddr);
write_mr(L4SYS_ARG2, shmflg);
/* Call pager with shmget() request. Check ipc error. */
if ((errno = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMAT)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, errno);
return (void *)-1;
if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMAT)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
return PTR_ERR(err);
}
/* Check if syscall itself was successful */
if ((errno = l4_get_retval()) < 0) {
printf("%s: SHMAT Error: %d.\n", __FUNCTION__, errno);
return (void *)-1;
if ((err = l4_get_retval()) < 0) {
printf("%s: SHMAT Error: %d.\n", __FUNCTION__, err);
return PTR_ERR(err);
}
/* Obtain shm base. */
return (void *)read_mr(L4SYS_ARG0);
}
static inline int l4_shmdt(const void *shmaddr)
int l4_shmdt(const void *shmaddr)
{
int err;
write_mr(L4SYS_ARG0, (unsigned long)shmaddr);
/* Call pager with shmget() request. Check ipc error. */
if ((errno = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMDT)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, errno);
if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_SHMDT)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
return -1;
}
/* Check if syscall itself was successful */
if ((errno = l4_get_retval()) < 0) {
printf("%s: SHMDT Error: %d.\n", __FUNCTION__, errno);
if ((err = l4_get_retval()) < 0) {
printf("%s: SHMDT Error: %d.\n", __FUNCTION__, err);
return -1;
}
return 0;
}
int shmget(key_t key, size_t size, int shmflg)
{
return l4_shmget(key, size, shmflg);
int ret = l4_shmget(key, size, shmflg);
/* If error, return positive error code */
if (ret < 0) {
errno = -ret;
return -1;
}
/* else return value */
return ret;
}
void *shmat(int shmid, const void *shmaddr, int shmflg)
{
return l4_shmat(shmid, shmaddr, shmflg);
void *ret = l4_shmat(shmid, shmaddr, shmflg);
/* If error, return positive error code */
if (IS_ERR(ret)) {
errno = -((int)ret);
return PTR_ERR(-1);
}
/* else return value */
return ret;
}
int shmdt(const void *shmaddr)
{
return l4_shmdt(shmaddr);
int ret = l4_shmdt(shmaddr);
/* If error, return positive error code */
if (ret < 0) {
errno = -ret;
return -1;
}
/* else return value */
return ret;
}

View File

@@ -59,13 +59,13 @@ def get_physical_base(source, target, env):
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'],
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror' ],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path, "-L" + libmem_path],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'libl4', 'libmm', 'libmc', 'libkm', \
'gcc', libc_name], # libgcc.a - This is required for division routines.
'gcc', libc_name], # libgcc.a - This is required for division routines.
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath, libc_incpath, kernel_incpath, \
libmem_incpath, libposix_incpath])

View File

@@ -64,6 +64,8 @@ void init_pm(struct initdata *initdata);
int start_init_tasks(struct initdata *initdata);
void dump_tasks(void);
void send_task_data(l4id_t requester);
/* Used by servers that have a reference to tcbs (e.g. a pager) */
#define current ((struct ktcb *)__L4_ARM_Utcb()->usr_handle)

View File

@@ -63,6 +63,10 @@ void handle_requests(void)
page_fault_handler(sender, (fault_kdata_t *)&mr[0]);
break;
case L4_IPC_TAG_TASKDATA:
send_task_data(sender);
break;
case L4_IPC_TAG_SHMGET: {
struct sys_shmget_args *args = (struct sys_shmget_args *)&mr[0];
sys_shmget(args->key, args->size, args->shmflg);

View File

@@ -494,4 +494,3 @@ int sys_brk(l4id_t sender, void *ds_end)
return 0;
}

View File

@@ -11,6 +11,7 @@
#include INC_GLUE(memory.h)
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/ipcdefs.h>
#include <lib/vaddr.h>
#include <task.h>
#include <kdata.h>
@@ -147,3 +148,31 @@ void init_pm(struct initdata *initdata)
start_init_tasks(initdata);
}
void send_task_data(l4id_t requester)
{
struct tcb *t;
int li, err;
if (requester != VFS_TID) {
printf("Task data is not requested by FS0, ignoring.\n");
return;
}
/* First word is total number of tcbs */
write_mr(L4SYS_ARG0, tcb_head.total);
/* Write each tcb's tid */
li = 0;
list_for_each_entry(t, &tcb_head.list, list) {
BUG_ON(li >= MR_USABLE_TOTAL);
write_mr(L4SYS_ARG1 + li, t->tid);
li++;
}
/* Reply */
if ((err = l4_ipc_return(0)) < 0) {
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
BUG();
}
}

View File

@@ -14,7 +14,7 @@ task_name = "test0"
# 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")
prev_image = join(project_root, "tasks/fs0/fs0.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"