mirror of
https://github.com/drasko/codezero.git
synced 2026-01-11 18:33:16 +01:00
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:
79
README
79
README
@@ -12,7 +12,7 @@ tasks that implement memory management, a virtual filesystem layer, and these
|
||||
servers currently support a small but essential subset of the POSIX API.
|
||||
|
||||
Codezero project is an effort to implement a modern, open source operating
|
||||
system based on the latest technology in microkernel design. It targets
|
||||
system based on the latest technology in microkernel and OS design. It targets
|
||||
realtime, high-end embedded systems and has an emphasis on the ARM architecture.
|
||||
|
||||
It is quite common to see open source projects developed in a closed-doors
|
||||
@@ -23,13 +23,32 @@ the Linux Kernel.
|
||||
|
||||
Why the name Codezero?
|
||||
|
||||
The project focuses on simplicity, elegance, cleanliness, which are assets
|
||||
usually hard to achieve in software engineering. The philosophy is to implement
|
||||
a structurally complete system with most modern and complex operating system
|
||||
features while retaining simplicity in the implementation as much as possible.
|
||||
Avoidance of code bloat is a short way to put it. This objective also fits well
|
||||
with embedded platforms, which usually have rigorous memory and performance
|
||||
requirements.
|
||||
The project focuses on simplicity, elegance, cleanliness, which are important
|
||||
assets in software engineering. The philosophy is to implement a structurally
|
||||
complete system with most modern OS features while retaining simplicity in the
|
||||
implementation as much as possible. This objective also fits well with embedded
|
||||
platforms, which usually have rigorous memory and performance requirements. Also
|
||||
the project is written from scratch, so the name emphasises that.
|
||||
|
||||
|
||||
Design & Features:
|
||||
|
||||
Codezero microkernel: Based on L4 microkernel principles, there are only a few
|
||||
system calls and the microkernel provides purely mechanism; threads and address
|
||||
spaces, and the methods of inter-process communication between them. Anything
|
||||
beyond these are policy and they are implemented in the userspace. Due to this
|
||||
rigorously simple design the microkernel can be used to design completely
|
||||
different operating systems. In terms of other features, the microkernel is
|
||||
preemptive, and smp-ready. Currently only synchronous communication is
|
||||
implemented, but this will change in the near future.
|
||||
|
||||
MM0: Implements memory management. It contains memory and page allocators. It
|
||||
implements demand paging by managing page faults, physical pages and their
|
||||
file/task associations.
|
||||
|
||||
FS0: Implements a simple, modern virtual filesystem layer. Since it abstracts
|
||||
the low-level filesystem details, it is a relatively easy job to port a new
|
||||
filesystem to be used under FS0.
|
||||
|
||||
|
||||
License:
|
||||
@@ -51,28 +70,32 @@ Why yet another Posix (micro) kernel?
|
||||
There are many open source Posix operating systems with advanced features such
|
||||
as *BSD and Linux. However these were originally not designed for embedded
|
||||
systems. Unix itself and all the tools built upon weren't meant for using on
|
||||
small devices. Besides, these operating systems naturally contain a lot of
|
||||
historical code. Linux is well established, and targets a broad range of
|
||||
platforms and uses, but consequently embedded platforms don't always get enough
|
||||
emphasis. Also such well established, mature systems tend to oppose major design
|
||||
overhauls, which limits innovation to a certain extent. In addition, their code
|
||||
base is so big, that it gets more and more difficult to understand how the
|
||||
system works. Usually %95 of the code is irrelevant to the problem, in case of
|
||||
embedded systems. Codezero is written from scratch to solely target embedded
|
||||
systems and as such the source code is %100 relevant. It is small and free from
|
||||
legacy code. Finally monolithic kernels may have issues with dependability due
|
||||
to much of the code sharing the same address space. Being a microkernel design,
|
||||
Codezero aims to defeat this problem and increase dependability.
|
||||
small devices. Accordingly, these operating systems contain a lot of historical
|
||||
code. Linux is well established, and targets a broad range of platforms and
|
||||
uses, but consequently embedded platforms don't always get enough emphasis. Also
|
||||
such well established, mature systems tend to oppose major design overhauls,
|
||||
which limits innovation to a certain extent. In addition, their code base is so
|
||||
big, that it gets more and more difficult to understand how the system works.
|
||||
Usually much of the code is irrelevant to the problem, in case of embedded
|
||||
systems. Codezero is written from scratch to solely target embedded systems and
|
||||
as such the source code is %100 relevant. It is small and free from legacy code.
|
||||
Finally monolithic kernels may have issues with dependability due to much of the
|
||||
code sharing the same address space. Being a microkernel design, Codezero aims
|
||||
to defeat this problem and increase dependability.
|
||||
|
||||
Other than these modern kernels, there is systems software targeting embedded
|
||||
devices. Most of them are proprietary, with their own users. Some of the open
|
||||
source ones are structurally too simplistic, and lack modern features such as
|
||||
paging. There are certainly existing well-designed embedded operating systems,
|
||||
but Codezero provides an alternative that will follow the open source
|
||||
development principles more closely. Finally, there are new ideas in OS
|
||||
literature that would improve Unix but aren't implemented either because they
|
||||
have no existing users or may break compatibility somewhat. (E.g. some are
|
||||
presented in Plan 9, or ReiserFS 4). As well as practising realistic development
|
||||
methodologies, Codezero project aims to keep up with the latest OS literature
|
||||
and provide the opportunity to incorporate the latest ideas in OS technology.
|
||||
paging. There are existing well-designed embedded OS'es, but Codezero provides
|
||||
an alternative that will follow the open source development principles more
|
||||
closely. This will prove useful because many embedded systems still use older
|
||||
development methods and the right open source methodology would prove favorable
|
||||
in the fast-paced nature of development (Linux has already proven that).
|
||||
|
||||
Finally, there are new ideas in OS literature that would improve Unix but aren't
|
||||
implemented either because they have no existing users or may break compatibility
|
||||
somewhat (e.g. some are presented in Plan 9). As well as practising realistic
|
||||
development methodologies, Codezero project aims to keep up with the latest OS
|
||||
literature and provide the opportunity to incorporate the latest ideas in OS
|
||||
technology.
|
||||
|
||||
|
||||
@@ -88,6 +88,10 @@
|
||||
#define printk printf
|
||||
#endif
|
||||
|
||||
/* Functions who may either return a pointer or an error code can use these: */
|
||||
#define PTR_ERR(x) ((void *)(x))
|
||||
#define IS_ERR(x) (((int)(x)) < 0)
|
||||
|
||||
/* TEST: Is this type of printk well tested? */
|
||||
#define BUG() {do { \
|
||||
printk("BUG in file: %s function: %s line: %d\n", \
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
.align 4
|
||||
.global bkpt_phys_to_virt;
|
||||
.type bkpt_phys_to_virt, function;
|
||||
.equ bkpt_phys_to_virt, 0x107118
|
||||
.equ bkpt_phys_to_virt, 0x106f88
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ void switch_to_user(struct ktcb *task)
|
||||
|
||||
void init_inittask(char *name, struct task_ids *ids)
|
||||
{
|
||||
struct svc_image *taskimg;
|
||||
struct svc_image *taskimg = 0;
|
||||
struct ktcb *task;
|
||||
int task_pages;
|
||||
|
||||
@@ -273,10 +273,12 @@ void init_inittask(char *name, struct task_ids *ids)
|
||||
*/
|
||||
for (int i = 0; i < bootdesc->total_images; i++) {
|
||||
if (!strcmp(name, bootdesc->images[i].name)) {
|
||||
BUG_ON(!(taskimg = &bootdesc->images[i]));
|
||||
taskimg = &bootdesc->images[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
BUG_ON(!taskimg);
|
||||
|
||||
printk("\nInitialising %s.\n", name);
|
||||
if (taskimg->phys_start & PAGE_MASK)
|
||||
printk("Warning, image start address not page aligned.\n");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __RAMDISK_H__
|
||||
#define __RAMDISK_H__
|
||||
|
||||
extern struct block_device ramdisk[];
|
||||
extern struct block_device ramdisk[];
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
void init_blkdev(void)
|
||||
{
|
||||
ramdisk.ops.open(&ramdisk);
|
||||
ramdisk[0].ops.init(&ramdisk[0]);
|
||||
ramdisk[1].ops.init(&ramdisk[1]);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
@@ -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
8
tasks/fs0/include/bdev.h
Normal 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
18
tasks/fs0/include/file.h
Normal 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__ */
|
||||
@@ -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
7
tasks/fs0/include/init.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef __INIT_H__
|
||||
#define __INIT_H__
|
||||
|
||||
/* FS0 initialisation */
|
||||
int initialise(void);
|
||||
|
||||
#endif /* __INIT_H__ */
|
||||
19
tasks/fs0/include/lib/malloc.h
Normal file
19
tasks/fs0/include/lib/malloc.h
Normal 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__ */
|
||||
@@ -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) { }
|
||||
|
||||
|
||||
@@ -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 = .;
|
||||
|
||||
@@ -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__ */
|
||||
97
tasks/fs0/include/memfs/memfs.h
Normal file
97
tasks/fs0/include/memfs/memfs.h
Normal 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__ */
|
||||
7
tasks/fs0/include/memfs/vnode.h
Normal file
7
tasks/fs0/include/memfs/vnode.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef __MEMFS_VNODE_H__
|
||||
#define __MEMFS_VNODE_H__
|
||||
|
||||
#include <fs.h>
|
||||
|
||||
|
||||
#endif /* __MEMFS_VNODE_H__ */
|
||||
@@ -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
14
tasks/fs0/src/bdev.c
Normal 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
29
tasks/fs0/src/c0fs/c0fs.c
Normal 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);
|
||||
}
|
||||
@@ -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
28
tasks/fs0/src/file.c
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
111
tasks/fs0/src/lookup.c
Normal 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
136
tasks/fs0/src/memfs/file.c
Normal 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
159
tasks/fs0/src/memfs/memfs.c
Normal 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
278
tasks/fs0/src/memfs/vnode.c
Normal 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,
|
||||
};
|
||||
|
||||
@@ -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
95
tasks/fs0/src/syscalls.c
Normal 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
107
tasks/fs0/src/task.c
Normal 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
36
tasks/fs0/src/vfs.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -494,4 +494,3 @@ int sys_brk(l4id_t sender, void *ds_end)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
cd build
|
||||
#arm-none-eabi-insight &
|
||||
qemu-system-arm -M versatilepb -kernel final.axf -nographic -s &
|
||||
qemu-system-arm -S -kernel final.axf -nographic -s -M versatilepb &
|
||||
sleep 0.5
|
||||
arm-none-eabi-insight ; pkill qemu-system-arm
|
||||
#arm-none-eabi-gdb ; pkill qemu-system-arm
|
||||
|
||||
Reference in New Issue
Block a user