diff --git a/fs/Makefile b/fs/Makefile new file mode 100644 index 0000000..a3f281a --- /dev/null +++ b/fs/Makefile @@ -0,0 +1,4 @@ +C_source := fs.c initrd.c +MODULE := fs + +include $(TOPDIR)/Makefile.inc diff --git a/fs/fs.c b/fs/fs.c new file mode 100644 index 0000000..ae15f02 --- /dev/null +++ b/fs/fs.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +vfs_node_t* fs_root = NULL; // The root of the filesystem. + +ssize_t read_fs(fildes_t* file, uint8_t* buffer, size_t size) +{ + vfs_node_t* node = file->node; + ssize_t ret = -EINVAL; + + if (BUILTIN_EXPECT(!node || !buffer, 0)) + return ret; + + spinlock_lock(&node->lock); + // Has the node got a read callback? + if (node->read != 0) + ret = node->read(file, buffer, size); + spinlock_unlock(&node->lock); + + return ret; +} + +ssize_t write_fs(fildes_t* file, uint8_t* buffer, size_t size) +{ + vfs_node_t* node = file->node; + ssize_t ret = -EINVAL; + + if (BUILTIN_EXPECT(!node || !buffer, 0)) + return ret; + + spinlock_lock(&node->lock); + // Has the node got a write callback? + if (node->write != 0) + ret = node->write(file, buffer, size); + spinlock_unlock(&node->lock); + + return ret; +} + +int open_fs(fildes_t* file, const char* name) +{ + uint32_t ret = 0, i, j = 1; + vfs_node_t* file_node = NULL; /* file node */ + vfs_node_t* dir_node = NULL; + char fname[MAX_FNAME]; + + if (BUILTIN_EXPECT(!name, 0)) + return ret; + + if (name[0] == '/') + file_node = fs_root; + + while((name[j] != '\0') || ((file_node != NULL) && (file_node->type == FS_DIRECTORY))) { + i = 0; + while((name[j] != '/') && (name[j] != '\0')) { + fname[i] = name[j]; + i++; j++; + } + fname[i] = '\0'; + dir_node = file_node; /* file must be a directory */ + file_node = finddir_fs(dir_node, fname); + if (name[j] == '/') + j++; + } + + //kprintf("dir_node = %p, file_node = %p, name = %s \n", dir_node, file_node, fname); + + /* file exists */ + if(file_node) { + spinlock_lock(&file_node->lock); + file->node = file_node; + // Has the file_node got an open callback? + if (file_node->open != 0) + ret = file->node->open(file, NULL); + spinlock_unlock(&file_node->lock); + } else if (dir_node) { /* file doesn't exist or opendir was called */ + spinlock_lock(&dir_node->lock); + file->node = dir_node; + // Has the dir_node got an open callback? + if (dir_node->open != 0) + ret = dir_node->open(file, fname); + spinlock_unlock(&dir_node->lock); + } else { + ret = -ENOENT; + } + + return ret; +} + +int close_fs(fildes_t* file) +{ + int ret = -EINVAL; + + if (BUILTIN_EXPECT(!(file->node), 0)) + return ret; + + spinlock_lock(&file->node->lock); + // Has the node got a close callback? + if (file->node->close != 0) + ret = file->node->close(file); + spinlock_unlock(&file->node->lock); + + return ret; +} + +struct dirent* readdir_fs(vfs_node_t * node, uint32_t index) +{ + struct dirent* ret = NULL; + + if (BUILTIN_EXPECT(!node, 0)) + return ret; + + spinlock_lock(&node->lock); + // Is the node a directory, and does it have a callback? + if ((node->type == FS_DIRECTORY) && node->readdir != 0) + ret = node->readdir(node, index); + spinlock_unlock(&node->lock); + + return ret; +} + +vfs_node_t* finddir_fs(vfs_node_t* node, const char *name) +{ + vfs_node_t* ret = NULL; + + if (BUILTIN_EXPECT(!node, 0)) + return ret; + + spinlock_lock(&node->lock); + // Is the node a directory, and does it have a callback? + if ((node->type == FS_DIRECTORY) && node->finddir != 0) + ret = node->finddir(node, name); + spinlock_unlock(&node->lock); + + return ret; +} + +vfs_node_t* mkdir_fs(vfs_node_t* node, const char *name) +{ + vfs_node_t* ret = NULL; + + if (BUILTIN_EXPECT(!node, 0)) + return ret; + + spinlock_lock(&node->lock); + if (node->mkdir != 0) + ret = node->mkdir(node, name); + spinlock_unlock(&node->lock); + + return ret; +} + +vfs_node_t* findnode_fs(const char* name) +{ + uint32_t i, j = 1; + vfs_node_t* ret = NULL; + char fname[MAX_FNAME]; + + if (BUILTIN_EXPECT(!name, 0)) + return ret; + + if (name[0] == '/') + ret = fs_root; + + while((name[j] != '\0') && ret) { + i = 0; + while((name[j] != '/') && (name[j] != '\0')) { + fname[i] = name[j]; + i++; j++; + } + fname[i] = '\0'; + ret = finddir_fs(ret, fname); + if (name[j] == '/') + j++; + } + + return ret; +} diff --git a/fs/initrd.c b/fs/initrd.c new file mode 100644 index 0000000..f763f5b --- /dev/null +++ b/fs/initrd.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static vfs_node_t initrd_root; + +#define INITRD_MAGIC_NUMBER 0x4711 + +/* + * Grub maps the initrd as module into the address space of the kernel. + * The module begins with the header "initrd_header_t", which describes + * the number of mounted files and the mount point. The header follows + * by the struct "initrd_file_desc_t" for each file, which will be mounted. + * This struct describes the file properties and the position in the + * module. + */ +typedef struct { + uint32_t magic; + uint32_t nfiles; + char mount_point[MAX_FNAME]; +} initrd_header_t; + +typedef struct { + uint32_t length; + uint32_t offset; + char fname[MAX_FNAME]; +} initrd_file_desc_t; + +static ssize_t initrd_read(fildes_t* file, uint8_t* buffer, size_t size) +{ + vfs_node_t* node = file->node; + + uint32_t i, pos = 0, found = 0; + off_t offset = 0; + char* data = NULL; + block_list_t* blist = &node->block_list; + + if (file->flags & O_WRONLY) + return -EACCES; + + /* init the tmp offset */ + offset = file->offset; + + /* searching for the valid data block */ + if (offset) { + pos = offset / node->block_size; + offset = offset % node->block_size; + } + do { + for(i=0; idata[i]) { + found++; + if (found > pos) + data = (char*) blist->data[i]; + } + } + + blist = blist->next; + } while(blist && !data); + + if (BUILTIN_EXPECT(!data, 0)) + return 0; + + /* + * If the data block is not large engough, + * we copy only the rest of the current block. + * The user has to restart the read operation + * for the next block. + */ + if ((offset + size) >= node->block_size) + size = node->block_size - offset; + + memcpy(buffer, data + offset, size); + + file->offset += size; + return size; +} + +static ssize_t initrd_emu_readdir(fildes_t* file, uint8_t* buffer, size_t size) +{ + vfs_node_t* node = file->node; + + uint32_t i, j, k, count; + uint32_t index = file->offset; + dirent_t* dirent; + dir_block_t* dirblock; + block_list_t* blist = &node->block_list; + + do { + for(i=0,count=0; idata[i]; + for(j=0; dirblock && jentries[j]; + if (dirent->vfs_node) { + count++; + if (count > index) { + k=0; + do { + buffer[k] = dirent->name[k]; + k++; + } while(dirent->name[k] != '\0'); + file->offset++; + return k; + } + } + } + } + + blist = blist->next; + } while(blist); + + return -EINVAL; +} + +static ssize_t initrd_write(fildes_t* file, uint8_t* buffer, size_t size) +{ + uint32_t i, pos = 0, found = 0; + off_t offset = 0; + char* data = NULL; + vfs_node_t* node = file->node; + block_list_t* blist = &node->block_list; + + if (file->flags & O_RDONLY) + return -EACCES; + + if (file->flags & O_APPEND) + file->offset = node->block_size; + + /* init the tmp offset */ + offset = file->offset; + + /* searching for the valid data block */ + if (offset) { + pos = offset / MAX_DATAENTRIES; + offset = offset % MAX_DATAENTRIES; + } + + do { + for (i = 0; i < MAX_DATABLOCKS && !data; i++) { + if ((size + offset) >= MAX_DATAENTRIES) + size = MAX_DATAENTRIES - offset; + if(!blist->data[i]) { + blist->data[i] = (data_block_t*) + kmalloc(sizeof(data_block_t)); + if (blist->data[i]) + memset(blist->data[i], 0x00, + sizeof(data_block_t)); + } + found++; + if (found > pos) { + data = (char*) blist->data[i]; + } + } + + if (!blist->next) { + blist->next = (block_list_t*) + kmalloc(sizeof(block_list_t)); + if (blist->next) + memset(blist->next, 0x00, + sizeof(block_list_t)); + } + blist = blist->next; + } while(blist && !data); + + /* you may have to increase nodesize */ + if (node->block_size < (file->offset + size)) + node->block_size = file->offset + size; + /* + * If the data block is not large engough, + * we copy only the rest of the current block. + * The user has to restart the write operation + * for the next block. + */ + memcpy(data + offset, buffer, size); + file->offset += size; + return size; +} + +static int initrd_open(fildes_t* file, const char* name) +{ + if (file->node->type == FS_FILE) { + if ((file->flags & O_CREAT) && (file->flags & O_EXCL)) + return -EEXIST; + + /* in the case of O_TRUNC kfree all the nodes */ + if (file->flags & O_TRUNC) { + uint32_t i; + char* data = NULL; + block_list_t* blist = &file->node->block_list; + block_list_t* lastblist = NULL; + + /* the first blist pointer have do remain valid. */ + for(i=0; idata[i]) { + kfree(blist->data[i], + sizeof(data_block_t)); + } + } + if (blist->next) { + lastblist = blist; + blist = blist->next; + lastblist->next = NULL; + + /* kfree all other blist pointers */ + do { + for(i=0; idata[i]) { + kfree(blist->data[i], sizeof(data_block_t)); + } + } + lastblist = blist; + blist = blist->next; + kfree(lastblist, sizeof(block_list_t)); + } while(blist); + } + + /* reset the block_size */ + file->node->block_size = 0; + } + } + + if (file->node->type == FS_DIRECTORY) { + + /* opendir was called: */ + if (name[0] == '\0') + return 0; + + /* open file was called: */ + if (!(file->flags & O_CREAT)) + return -ENOENT; + + uint32_t i, j; + block_list_t* blist = NULL; + /* CREATE FILE */ + vfs_node_t* new_node = kmalloc(sizeof(vfs_node_t)); + if (BUILTIN_EXPECT(!new_node, 0)) + return -EINVAL; + + blist = &file->node->block_list; + dir_block_t* dir_block; + dirent_t* dirent; + + memset(new_node, 0x00, sizeof(vfs_node_t)); + new_node->type = FS_FILE; + new_node->read = initrd_read; + new_node->write = initrd_write; + new_node->open = initrd_open; + spinlock_init(&new_node->lock); + + /* create a entry for the new node in the directory block of current node */ + do { + for(i=0; idata[i]) { + dir_block = (dir_block_t*) blist->data[i]; + for(j=0; jentries[j]; + if (!dirent->vfs_node) { + dirent->vfs_node = new_node; + strncpy(dirent->name, (char*) name, MAX_FNAME); + goto exit_create_file; // there might be a better Solution *************** + } + } + } + } + /* if all blocks are reserved, we have to allocate a new one */ + if (!blist->next) { + blist->next = (block_list_t*) kmalloc(sizeof(block_list_t)); + if (blist->next) + memset(blist->next, 0x00, sizeof(block_list_t)); + } + + blist = blist->next; + } while(blist); + +exit_create_file: + file->node = new_node; + file->node->block_size = 0; + + } + return 0; +} + + +static dirent_t* initrd_readdir(vfs_node_t* node, uint32_t index) +{ + uint32_t i, j, count; + dirent_t* dirent; + dir_block_t* dirblock; + block_list_t* blist = &node->block_list; + + do { + for(i=0,count=0; idata[i]; + for(j=0; dirblock && jentries[j]; + if (dirent->vfs_node) { + count++; + if (count > index) + return dirent; + } + } + } + + blist = blist->next; + } while(blist); + + return NULL; +} + +static vfs_node_t* initrd_finddir(vfs_node_t* node, const char *name) +{ + uint32_t i, j; + dir_block_t* dirblock; + dirent_t* dirent; + block_list_t* blist = &node->block_list; + + do { + for(i=0; idata[i]; + for(j=0; dirblock && jentries[j]; + if (!strncmp(dirent->name, name, MAX_FNAME)) + return dirent->vfs_node; + } + } + + blist = blist->next; + } while(blist); + + return NULL; +} + +static vfs_node_t* initrd_mkdir(vfs_node_t* node, const char* name) +{ + uint32_t i, j; + dir_block_t* dir_block; + dir_block_t* tmp; + dirent_t* dirent; + vfs_node_t* new_node; + block_list_t* blist = &node->block_list; + + if (BUILTIN_EXPECT(node->type != FS_DIRECTORY, 0)) + return NULL; + + /* exists already a entry with same name? */ + if (initrd_finddir(node, name)) + return NULL; + + new_node = kmalloc(sizeof(vfs_node_t)); + if (BUILTIN_EXPECT(!new_node, 0)) + return NULL; + + memset(new_node, 0x00, sizeof(vfs_node_t)); + new_node->type = FS_DIRECTORY; + new_node->read = &initrd_emu_readdir; + new_node->readdir = &initrd_readdir; + new_node->finddir = &initrd_finddir; + new_node->mkdir = &initrd_mkdir; + new_node->open = &initrd_open; + spinlock_init(&new_node->lock); + + /* create default directory entry */ + dir_block = (dir_block_t*) kmalloc(sizeof(dir_block_t)); + if (BUILTIN_EXPECT(!dir_block, 0)) + goto out; + memset(dir_block, 0x00, sizeof(dir_block_t)); + new_node->block_list.data[0] = dir_block; + strncpy(dir_block->entries[0].name, ".", MAX_FNAME); + dir_block->entries[0].vfs_node = new_node; + strncpy(dir_block->entries[1].name, "..", MAX_FNAME); + dir_block->entries[1].vfs_node = node; + + do { + /* searching for a free directory block */ + for(i=0; idata[i]) { + tmp = (dir_block_t*) blist->data[i]; + for(j=0; jentries[j]; + if (!dirent->vfs_node) { + dirent->vfs_node = new_node; + strncpy(dirent->name, name, MAX_FNAME); + return new_node; + } + } + } + } + + /* if all blocks are reserved, we have to allocate a new one */ + if (!blist->next) { + blist->next = (block_list_t*) kmalloc(sizeof(block_list_t)); + if (blist->next) + memset(blist->next, 0x00, sizeof(block_list_t)); + } + + blist = blist->next; + } while(blist); + + kfree(dir_block, sizeof(dir_block_t)); +out: + kfree(new_node, sizeof(vfs_node_t)); + + return NULL; +} + +int initrd_init(void) +{ + dir_block_t* dir_block; + vfs_node_t* tmp; + uint32_t i, j, k, l; + uint32_t mods_count = 0; + multiboot_module_t* mmodule = NULL; + + if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MODS)) { + mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr); + mods_count = mb_info->mods_count; + } + + /* Initialize the root directory. */ + fs_root = &initrd_root; + memset(&initrd_root, 0x00, sizeof(vfs_node_t)); + initrd_root.type = FS_DIRECTORY; + initrd_root.read = &initrd_emu_readdir; + initrd_root.readdir = &initrd_readdir; + initrd_root.finddir = &initrd_finddir; + initrd_root.mkdir = &initrd_mkdir; + initrd_root.open = &initrd_open; + spinlock_init(&initrd_root.lock); + + /* create default directory block */ + dir_block = (dir_block_t*) kmalloc(sizeof(dir_block_t)); + if (BUILTIN_EXPECT(!dir_block, 0)) + return -ENOMEM; + memset(dir_block, 0x00, sizeof(dir_block_t)); + initrd_root.block_list.data[0] = dir_block; + strncpy(dir_block->entries[0].name, ".", MAX_FNAME); + dir_block->entries[0].vfs_node = fs_root; + strncpy(dir_block->entries[1].name, "..", MAX_FNAME); + dir_block->entries[1].vfs_node = fs_root; + + /* create the directory bin and dev */ + mkdir_fs(fs_root, "bin"); + mkdir_fs(fs_root, "sbin"); + tmp = mkdir_fs(fs_root, "dev"); + + /* create the character device "kmessages" */ + tmp = mkdir_fs(fs_root, "var"); + kmsg_init(tmp, "log"); + + /* For every module.. */ + for(i=0; imagic != INITRD_MAGIC_NUMBER, 0)) { + kprintf("Invalid magic number for a init ram disk: 0x%x\n", header->magic); + continue; + } + + tmp = findnode_fs(header->mount_point); + if (BUILTIN_EXPECT(!tmp, 0)) { + kprintf("Did not found mount point %s.\n", header->mount_point); + continue; + } + + if (BUILTIN_EXPECT(tmp->type != FS_DIRECTORY, 0)) { + kprintf("%s is not a valid mount point.\n", header->mount_point); + continue; + } + + file_desc = (initrd_file_desc_t*) (header + 1); + for(j=0; jnfiles; j++) { + block_list_t* blist; + dir_block_t* dir_block; + dirent_t* dirent; + + if (finddir_fs(tmp, file_desc->fname)) { + kprintf("Error: %s alreay exits\n", file_desc->fname); + goto next_file; + } + + /* create a new node and map the module as data block */ + new_node = kmalloc(sizeof(vfs_node_t)); + if (BUILTIN_EXPECT(!new_node, 0)) { + kprintf("Not enough memory to create new initrd node\n"); + goto next_file; + } + memset(new_node, 0x00, sizeof(vfs_node_t)); + new_node->type = FS_FILE; + new_node->read = initrd_read; + new_node->write = initrd_write; + new_node->open = initrd_open; + new_node->block_size = file_desc->length; + new_node->block_list.data[0] = ((char*) header) + file_desc->offset; + spinlock_init(&new_node->lock); + + /* create a entry for the new node in the directory block of current node */ + blist = &tmp->block_list; + do { + for(k=0; kdata[k]) { + dir_block = (dir_block_t*) blist->data[k]; + for(l=0; lentries[l]; + if (!dirent->vfs_node) { + dirent->vfs_node = new_node; + strncpy(dirent->name, file_desc->fname, MAX_FNAME); + goto next_file; + } + } + } + } + + /* if all blocks are reserved, we have to allocate a new one */ + if (!blist->next) { + blist->next = (block_list_t*) kmalloc(sizeof(block_list_t)); + if (blist->next) + memset(blist->next, 0x00, sizeof(block_list_t)); + } + + blist = blist->next; + } while(blist); +next_file: + file_desc++; + } + } + + return 0; +} diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index 45cd18e..4945eeb 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -34,6 +34,7 @@ extern "C" { #define EDUOS_VERSION "0.1" #define MAX_TASKS 16 +#define MAX_FNAME 128 #define TIMER_FREQ 100 /* in HZ */ #define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */ #define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */ diff --git a/kernel/main.c b/kernel/main.c index d69205c..de1d8f4 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -126,6 +126,7 @@ static int eduos_init(void) #ifdef CONFIG_UART uart_init(); #endif + initrd_init(); return 0; } diff --git a/libkern/stdio.c b/libkern/stdio.c index 6b302f0..5579c4b 100644 --- a/libkern/stdio.c +++ b/libkern/stdio.c @@ -26,9 +26,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -52,6 +54,102 @@ static spinlock_irqsave_t olock = SPINLOCK_IRQSAVE_INIT; static atomic_int32_t kmsg_counter = ATOMIC_INIT(0); static unsigned char kmessages[KMSG_SIZE] __attribute__ ((section(".kmsg"))) = {[0 ... KMSG_SIZE-1] = 0x00}; +static ssize_t kmsg_read(fildes_t* file, uint8_t* buffer, size_t size) +{ + size_t start, i = 0; + + if (BUILTIN_EXPECT(!buffer, 0)) + return -EINVAL; + if (BUILTIN_EXPECT(!size, 0)) + return 0; + + if (kmessages[(atomic_int32_read(&kmsg_counter) + 1) % KMSG_SIZE] == 0) + start = 0; + else + start = (atomic_int32_read(&kmsg_counter) + 1) % KMSG_SIZE; + + if (((start + file->offset) % KMSG_SIZE) == atomic_int32_read(&kmsg_counter)) + return 0; + if (file->offset >= KMSG_SIZE) + return 0; + + for(i=0; ioffset++) { + buffer[i] = kmessages[(start + file->offset) % KMSG_SIZE]; + if (((start + file->offset) % KMSG_SIZE) == atomic_int32_read(&kmsg_counter)) + return i; + } + + return size; +} + +static int kmsg_open(fildes_t* file, const char *name) +{ + return 0; +} + +static int kmsg_close(fildes_t* file) +{ + return 0; +} + +/* Init Functions */ +int kmsg_init(vfs_node_t * node, const char *name) +{ + uint32_t i, j; + vfs_node_t* new_node; + dir_block_t* blockdir; + dirent_t* dirent; + block_list_t* blist; + + if (BUILTIN_EXPECT(!node || !name, 0)) + return -EINVAL; + + if (BUILTIN_EXPECT(node->type != FS_DIRECTORY, 0)) + return -EINVAL; + + if (finddir_fs(node, name)) + return -EINVAL; + + new_node = kmalloc(sizeof(vfs_node_t)); + if (BUILTIN_EXPECT(!new_node, 0)) + return -ENOMEM; + + memset(new_node, 0x00, sizeof(vfs_node_t)); + new_node->type = FS_CHARDEVICE; + new_node->open = &kmsg_open; + new_node->close = &kmsg_close; + new_node->read = &kmsg_read; + new_node->write = NULL; + spinlock_init(&new_node->lock); + + blist = &node->block_list; + do { + for (i = 0; i < MAX_DATABLOCKS; i++) { + if (blist->data[i]) { + blockdir = (dir_block_t *) blist->data[i]; + for (j = 0; j < MAX_DIRENTRIES; j++) { + dirent = &blockdir->entries[j]; + if (!dirent->vfs_node) { + dirent->vfs_node = new_node; + strncpy(dirent->name, name, MAX_FNAME); + return 0; + } + } + } + } + + if (!blist->next) { + blist->next = (block_list_t *) kmalloc(sizeof(block_list_t)); + if (blist->next) + memset(blist->next, 0x00, sizeof(block_list_t)); + } + } while (blist); + + kfree(new_node, sizeof(vfs_node_t)); + + return -ENOMEM; +} + int koutput_init(void) { #ifdef CONFIG_VGA