diff --git a/Makefile.example b/Makefile.example index e5dc3b3d..5c9f63b0 100644 --- a/Makefile.example +++ b/Makefile.example @@ -1,7 +1,7 @@ export TOPDIR = /home/stefan/SCC/MetalSVM export ARCH = x86 NAME = metalsvm.bin -KERNDIRS = libkern kernel mm arch lwip drivers +KERNDIRS = libkern kernel mm fs arch lwip drivers SUBDIRS = libgloss $(KERNDIRS) OBJS = $(shell for i in $(KERNDIRS); do find $$i -name *.o; done) diff --git a/NOTICE b/NOTICE index 3374f824..abab9062 100644 --- a/NOTICE +++ b/NOTICE @@ -51,3 +51,10 @@ proprietary applications can adopt newlib because its use does not require distribution of the end work's source code. For convenience, all of newlib's licenses are gathered up into the file COPYING.NEWLIB, which is included in the directory newlib or in newlib's source code. + +========================================================================= += JamesM's kernel development tutorials = +========================================================================= +MetalSVM's virtual filesystem and its initial ramdiks is is derived from +JamesM's kernel development tutorials. +(http://www.jamesmolloy.co.uk/tutorial_html/index.html) diff --git a/arch/x86/include/asm/stddef.h b/arch/x86/include/asm/stddef.h index d18c521c..19df6f1c 100644 --- a/arch/x86/include/asm/stddef.h +++ b/arch/x86/include/asm/stddef.h @@ -25,6 +25,7 @@ extern "C" { #endif typedef unsigned int size_t; +typedef int ptrdiff_t; /* This defines what the stack looks like after an ISR was running */ struct state { diff --git a/fs/Makefile b/fs/Makefile new file mode 100644 index 00000000..1f21bc55 --- /dev/null +++ b/fs/Makefile @@ -0,0 +1,20 @@ +C_source = fs.c initrd.c + +OBJS += $(patsubst %.c, %.o, $(filter %.c, $(C_source))) + +# other implicit rules +%.o : %.c + $(CC) -c $(CFLAGS) -o $@ $< + +default: $(OBJS) + +all: $(OBJS) + +clean: + $(RM) *.o *~ $(NAME) + +depend: + $(CC) -MM $(CFLAGS) $(C_source) > Makefile.dep + +-include Makefile.dep +# DO NOT DELETE diff --git a/fs/fs.c b/fs/fs.c new file mode 100644 index 00000000..3dfebe0a --- /dev/null +++ b/fs/fs.c @@ -0,0 +1,72 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#include + +fs_node_t *fs_root = NULL; // The root of the filesystem. + +uint32_t read_fs(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) +{ + // Has the node got a read callback? + if (node->read != 0) + return node->read(node, offset, size, buffer); + else + return 0; +} + +uint32_t write_fs(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) +{ + // Has the node got a write callback? + if (node->write != 0) + return node->write(node, offset, size, buffer); + else + return 0; +} + +void open_fs(fs_node_t * node, uint8_t read, uint8_t write) +{ + // Has the node got an open callback? + if (node->open != 0) + return node->open(node); +} + +void close_fs(fs_node_t * node) +{ + // Has the node got a close callback? + if (node->close != 0) + return node->close(node); +} + +struct dirent *readdir_fs(fs_node_t * node, uint32_t index) +{ + // Is the node a directory, and does it have a callback? + if ((node->flags & 0x7) == FS_DIRECTORY && node->readdir != 0) + return node->readdir(node, index); + else + return NULL; +} + +fs_node_t *finddir_fs(fs_node_t * node, char *name) +{ + // Is the node a directory, and does it have a callback? + if ((node->flags & 0x7) == FS_DIRECTORY && node->finddir != 0) + return node->finddir(node, name); + else + return NULL; +} diff --git a/fs/initrd.c b/fs/initrd.c new file mode 100644 index 00000000..6a5c007c --- /dev/null +++ b/fs/initrd.c @@ -0,0 +1,150 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#include +#include +#include +#include +#include + +initrd_header_t *initrd_header; // The header. +initrd_file_header_t *file_headers; // The list of file headers. +fs_node_t *initrd_root; // Our root directory node. +fs_node_t *initrd_dev; // We also add a directory node for /dev, so we can mount devfs later on. +fs_node_t *root_nodes; // List of file nodes. +int nroot_nodes; // Number of file nodes. + +struct dirent dirent; + +static uint32_t initrd_read(fs_node_t * node, uint32_t offset, uint32_t size, + uint8_t * buffer) +{ + initrd_file_header_t header = file_headers[node->inode]; + if (offset > header.length) + return 0; + if (offset + size > header.length) + size = header.length - offset; + memcpy(buffer, (uint8_t *) (header.offset + offset), size); + return size; +} + +static struct dirent *initrd_readdir(fs_node_t * node, uint32_t index) +{ + if (node == initrd_root && index == 0) { + strcpy(dirent.name, "dev"); + dirent.name[3] = 0; + dirent.ino = 0; + return &dirent; + } + + if (index - 1 >= nroot_nodes) + return NULL; + strcpy(dirent.name, root_nodes[index - 1].name); + dirent.name[strlen(root_nodes[index - 1].name)] = 0; + dirent.ino = root_nodes[index - 1].inode; + return &dirent; +} + +static fs_node_t *initrd_finddir(fs_node_t * node, char *name) +{ + int i; + + if (node == initrd_root && !strcmp(name, "dev")) + return initrd_dev; + + for (i = 0; i < nroot_nodes; i++) + if (!strcmp(name, root_nodes[i].name)) + return &root_nodes[i]; + return NULL; +} + +void initrd_init(void) +{ + uint32_t i, location = 0; + +#ifdef CONFIG_MULTIBOOT + if (mb_info && (mb_info->flags & (1 << (3)))) { + multiboot_module_t* mmodule = (multiboot_module_t*) mb_info->mods_addr; + location = mmodule->mod_start; + } +#endif + + // Initialise the main and file header pointers and populate the root directory. + initrd_header = (initrd_header_t *) location; + file_headers = + (initrd_file_header_t *) (location + sizeof(initrd_header_t)); + + // Initialise the root directory. + initrd_root = (fs_node_t *) kmalloc(sizeof(fs_node_t)); + strcpy(initrd_root->name, "/"); + initrd_root->mask = initrd_root->uid = initrd_root->gid = + initrd_root->inode = initrd_root->length = 0; + initrd_root->flags = FS_DIRECTORY; + initrd_root->read = 0; + initrd_root->write = 0; + initrd_root->open = 0; + initrd_root->close = 0; + initrd_root->readdir = &initrd_readdir; + initrd_root->finddir = &initrd_finddir; + initrd_root->ptr = 0; + initrd_root->impl = 0; + + // Initialise the /dev directory (required!) + initrd_dev = (fs_node_t *) kmalloc(sizeof(fs_node_t)); + strcpy(initrd_dev->name, "dev"); + initrd_dev->mask = initrd_dev->uid = initrd_dev->gid = + initrd_dev->inode = initrd_dev->length = 0; + initrd_dev->flags = FS_DIRECTORY; + initrd_dev->read = 0; + initrd_dev->write = 0; + initrd_dev->open = 0; + initrd_dev->close = 0; + initrd_dev->readdir = &initrd_readdir; + initrd_dev->finddir = &initrd_finddir; + initrd_dev->ptr = 0; + initrd_dev->impl = 0; + + root_nodes = + (fs_node_t *) kmalloc(sizeof(fs_node_t) * initrd_header->nfiles); + nroot_nodes = initrd_header->nfiles; + + // For every file... + for(i=0; infiles; i++) { + // Edit the file's header - currently it holds the file offset + // relative to the start of the ramdisk. We want it relative to the start + // of memory. + file_headers[i].offset += location; + // Create a new file node. + strncpy(root_nodes[i].name, file_headers[i].name, MAX_FNAME); + root_nodes[i].mask = root_nodes[i].uid = root_nodes[i].gid = 0; + root_nodes[i].length = file_headers[i].length; + root_nodes[i].inode = i; + root_nodes[i].flags = FS_FILE; + root_nodes[i].read = &initrd_read; + root_nodes[i].write = 0; + root_nodes[i].readdir = 0; + root_nodes[i].finddir = 0; + root_nodes[i].open = 0; + root_nodes[i].close = 0; + root_nodes[i].impl = 0; + } + + /* In our case, initrd is also the root of our file system */ + fs_root = initrd_root; +} diff --git a/include/metalsvm/fs.h b/include/metalsvm/fs.h new file mode 100644 index 00000000..9852e0ea --- /dev/null +++ b/include/metalsvm/fs.h @@ -0,0 +1,80 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#ifndef __FS_H__ +#define __FS_H__ + +#include + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 +#define FS_BLOCKDEVICE 0x04 +#define FS_PIPE 0x05 +#define FS_SYMLINK 0x06 +#define FS_MOUNTPOINT 0x08 // Is the file an active mountpoint? + +struct fs_node; + +/* These typedefs define the type of callbacks - called when read/write/open/close are called. */ +typedef uint32_t(*read_type_t) (struct fs_node *, uint32_t, uint32_t, uint8_t *); +typedef uint32_t(*write_type_t) (struct fs_node *, uint32_t, uint32_t, uint8_t *); +typedef void (*open_type_t) (struct fs_node *); +typedef void (*close_type_t) (struct fs_node *); +typedef struct dirent *(*readdir_type_t) (struct fs_node *, uint32_t); +typedef struct fs_node *(*finddir_type_t) (struct fs_node *, char *name); + +typedef struct fs_node { + char name[MAX_FNAME]; // The filename. + uint32_t mask; // The permissions mask. + uint32_t uid; // The owning user. + uint32_t gid; // The owning group. + uint32_t flags; // Includes the node type. See #defines above. + uint32_t inode; // This is device-specific - provides a way for a filesystem to identify files. + uint32_t length; // Size of the file, in bytes. + uint32_t impl; // An implementation-defined number. + read_type_t read; + write_type_t write; + open_type_t open; + close_type_t close; + readdir_type_t readdir; + finddir_type_t finddir; + struct fs_node *ptr; // Used by mountpoints and symlinks. +} fs_node_t; + +struct dirent { + char name[MAX_FNAME]; // Filename. + uint32_t ino; // Inode number. Required by POSIX. +}; + +extern fs_node_t *fs_root; // The root of the filesystem. + +/* + * Standard read/write/open/close functions. Note that these are all suffixed with + * _fs to distinguish them from the read/write/open/close which deal with file descriptors, + * not file nodes. + */ +uint32_t read_fs(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer); +uint32_t write_fs(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer); +void open_fs(fs_node_t * node, uint8_t read, uint8_t write); +void close_fs(fs_node_t * node); +struct dirent *readdir_fs(fs_node_t * node, uint32_t index); +fs_node_t *finddir_fs(fs_node_t * node, char *name); + +#endif diff --git a/include/metalsvm/initrd.h b/include/metalsvm/initrd.h new file mode 100644 index 00000000..8736c0eb --- /dev/null +++ b/include/metalsvm/initrd.h @@ -0,0 +1,38 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#ifndef __INITRD_H__ +#define __INITRD_H__ + +#include + +typedef struct { + uint32_t nfiles; // The number of files in the ramdisk. +} initrd_header_t; + +typedef struct { + uint8_t magic; // Magic number, for error checking. + char name[MAX_FNAME]; // Filename. + uint32_t offset; // Offset in the initrd that the file starts. + uint32_t length; // Length of the file. +} initrd_file_header_t; + +void initrd_init(void); + +#endif diff --git a/include/metalsvm/string.h b/include/metalsvm/string.h index 23b0f747..a7b19bc7 100644 --- a/include/metalsvm/string.h +++ b/include/metalsvm/string.h @@ -48,6 +48,10 @@ char* strncpy(char *dest, const char *src, size_t n); char* strcpy(char *dest, const char *src); #endif +#ifndef HAVE_ARCH_STRCMP +int strcmp(const char *s1, const char *s2); +#endif + #ifdef __cplusplus } #endif diff --git a/kernel/main.c b/kernel/main.c index 5c253a8c..11f07210 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,35 @@ extern int test_init(void); extern const void kernel_start; extern const void kernel_end; -unsigned long user_tasks[MAX_TASKS] = {[0 ... MAX_TASKS-1] = 0}; + +static void list_root(void) +{ + // list the contents of / + int i = 0; + struct dirent *node = NULL; + + while ((node = readdir_fs(fs_root, i)) != 0) { + kprintf("Found file %s\n", node->name); + fs_node_t *fsnode = finddir_fs(fs_root, node->name); + + if ((fsnode->flags&0x7) == FS_DIRECTORY) + kputs("\t(directory)\n"); + else { + char buf[256]; + uint32_t sz; + int j; + + kputs("\t contents: \""); + sz = read_fs(fsnode, 0, 256, buf); + + for (j = 0; j < sz; j++) + kputchar(buf[j]); + + kputs("\"\n"); + } + i++; + } +} #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) err_t sccpcif_init(struct netif* netif); @@ -97,7 +126,6 @@ int STDCALL scc_pc_task(void* arg) int main(void) { - unsigned int i; #ifdef CONFIG_LWIP tid_t pc_id; #endif @@ -113,6 +141,7 @@ int main(void) mmu_init(); multitasking_init(); koutput_init(); + initrd_init(); irq_enable(); @@ -130,11 +159,9 @@ int main(void) timer_set_frequency(TIMER_FREQ); sleep(5); + list_root(); test_init(); - for(i=0; (iflags & (1 << (3)))) { multiboot_module_t* mmodule = (multiboot_module_t*) mb_info->mods_addr; - elf_header_t* header; - elf_program_header_t* ph; - int j; for(i=0; imods_count; i++, mmodule++) { - header = (elf_header_t*) mmodule->mod_start; - - /* Did we found a ELF-file? */ - if (header->magic != ELF_MAGIC) { - kprintf("Bad magic number!!!\n"); - continue; - } - - if (ientry; - else - kprintf("Too many tasks!!!\n"); - kprintf("Entry point of task %i at %lx\n", i, user_tasks[i]); - - ph = (elf_program_header_t*) (((char*) mmodule->mod_start) + header->ph_offset); - for (j=0; jph_entry_count; j++, ph++) { - void* dest = (void*) ph->virt_addr; - void* src = ((char*) mmodule->mod_start) + ph->offset; - - /* We load only regions from typ LOAD into the memory */ - if (ph->type != PT_LOAD) - continue; - if (!dest) - continue; - - memset(dest, 0, ph->mem_size); - memcpy(dest, src, ph->file_size); - - addr = (size_t) dest; - while(addr < ph->mem_size) { - page_set_mark(addr / PAGE_SIZE); - addr += PAGE_SIZE; - atomic_int32_inc(&total_allocated_pages); - atomic_int32_dec(&total_available_pages); - } + for(addr=mmodule->mod_start; addrmod_end; addr+=PAGE_SIZE) { + page_set_mark(addr / PAGE_SIZE); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); } } } diff --git a/newlib/examples/Makefile b/newlib/examples/Makefile index 7c4e24a2..0aeabe16 100644 --- a/newlib/examples/Makefile +++ b/newlib/examples/Makefile @@ -1,6 +1,6 @@ MAKE = make CC = gcc -CFLAGS = -O2 -nostdinc -fno-stack-protector -fno-builtin -I../current/include -I../../include -I../../arch/x86/include +CFLAGS = -O2 -nostdinc -Wall -fno-builtin -I../current/include -I../../include -I../../arch/x86/include -fno-stack-protector LDFLGAS = -nostdlib -L../current/lib/ # other implicit rules diff --git a/newlib/examples/hello.c b/newlib/examples/hello.c index 717f548f..776643e6 100644 --- a/newlib/examples/hello.c +++ b/newlib/examples/hello.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #undef errno extern int errno; diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 00000000..fe2546b2 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,23 @@ +MAKE = make +CC = gcc +CFLAGS = -O2 -Wall +LDFLGAS = + +# other implicit rules +%.o : %.c + $(CC) -c $(CFLAGS) -o $@ $< + +default: + $(MAKE) all + +all: make_initrd.o + $(CC) $(CFLAGS) -o make_initrd $< $(LDFLAGS) + +clean: + $(RM) *.o *~ + +depend: + $(CC) -MM $(CFLAGS) *.c > Makefile.dep + +-include Makefile.dep +# DO NOT DELETE diff --git a/tools/make_initrd.c b/tools/make_initrd.c new file mode 100644 index 00000000..139e18f4 --- /dev/null +++ b/tools/make_initrd.c @@ -0,0 +1,81 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#include +#include +#include + +struct initrd_header { + unsigned char magic; + char name[128]; + unsigned int offset; + unsigned int length; +}; + +int main(int argc, char **argv) +{ + + int i, nheaders = (argc - 1) / 2; + struct initrd_header headers[64]; + unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int); + + memset(headers, 0x00, 64*sizeof(struct initrd_header)); + printf("size of header: %d\n", sizeof(struct initrd_header)); + + for (i = 0; i < nheaders; i++) { + printf("writing file %s->%s at 0x%x\n", argv[i * 2 + 1], + argv[i * 2 + 2], off); + strcpy(headers[i].name, argv[i * 2 + 2]); + headers[i].offset = off; + FILE *stream = fopen(argv[i * 2 + 1], "r"); + if (stream == 0) { + printf("Error: file not found: %s\n", argv[i * 2 + 1]); + return 1; + } + fseek(stream, 0, SEEK_END); + headers[i].length = ftell(stream); + off += headers[i].length; + fclose(stream); + headers[i].magic = 0xBF; + } + + FILE *wstream = fopen("./initrd.img", "w"); + unsigned char *data = (unsigned char *)malloc(off); + fwrite(&nheaders, sizeof(int), 1, wstream); + fwrite(headers, sizeof(struct initrd_header), 64, wstream); + + for (i = 0; i < nheaders; i++) { + FILE *stream = fopen(argv[i * 2 + 1], "r"); + unsigned char *buf = (unsigned char *)malloc(headers[i].length); + size_t curr, len = headers[i].length; + + do { + curr = fread(buf, 1, len, stream); + fwrite(buf, 1, len, wstream); + len -= curr; + } while(len > 0); + fclose(stream); + free(buf); + } + + fclose(wstream); + free(data); + + return 0; +}