- add a simple virtual filesystem and as simple initial ramdisk

git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@102 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
stefan 2010-08-17 21:20:03 +00:00
parent bda5f3618e
commit 5cfbfb5a32
17 changed files with 535 additions and 47 deletions

View file

@ -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)

7
NOTICE
View file

@ -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)

View file

@ -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 {

20
fs/Makefile Normal file
View file

@ -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

72
fs/fs.c Normal file
View file

@ -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 <metalsvm/fs.h>
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;
}

150
fs/initrd.c Normal file
View file

@ -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 <metalsvm/stdlib.h>
#include <metalsvm/stdio.h>
#include <metalsvm/string.h>
#include <metalsvm/initrd.h>
#include <asm/multiboot.h>
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; i<initrd_header->nfiles; 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;
}

80
include/metalsvm/fs.h Normal file
View file

@ -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 <metalsvm/stddef.h>
#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

38
include/metalsvm/initrd.h Normal file
View file

@ -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 <metalsvm/fs.h>
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

View file

@ -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

View file

@ -23,6 +23,7 @@
#include <metalsvm/mmu.h>
#include <metalsvm/tasks.h>
#include <metalsvm/processor.h>
#include <metalsvm/initrd.h>
#include <asm/irq.h>
#include <asm/irqflags.h>
#include <asm/kb.h>
@ -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; (i<MAX_TASKS) && user_tasks[i]; i++)
create_user_task(NULL, (entry_point_t)user_tasks[i], NULL, 0);
#ifdef CONFIG_LWIP
create_kernel_task(&pc_id, scc_pc_task, NULL);
#endif

View file

@ -63,7 +63,7 @@ typedef unsigned short u_short;
typedef unsigned long long u_quad_t;
typedef long long quad_t;
typedef unsigned long uintptr_t;
typedef long ptrdiff_t;
//typedef long ptrdiff_t;
#define NBBY 8 /* number of bits in a byte */
char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define hex2ascii(hex) (hex2ascii_data[hex])

View file

@ -98,3 +98,21 @@ char* strcpy(char *dest, const char *src)
return dest;
}
#endif
#ifndef HAVE_ARCH_STRCMP
int strcmp(const char *s1, const char *s2)
{
int ret = 0;
do {
ret = (int) (*s1 - *s2);
s1++; s2++;
} while ((*s1 != '\0') && (*s2 != '\0') && !ret);
if (!ret)
ret = (int) (*s1 - *s2);
return ret;
}
#endif

View file

@ -43,7 +43,6 @@ atomic_int32_t total_available_pages = ATOMIC_INIT(0);
extern const void kernel_start;
extern const void kernel_end;
extern unsigned long user_tasks[MAX_TASKS];
inline static int page_marked(unsigned int i)
{
@ -118,46 +117,12 @@ int mmu_init(void)
if (mb_info && (mb_info->flags & (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; i<mb_info->mods_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 (i<MAX_TASKS)
user_tasks[i] = header->entry;
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; j<header->ph_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; addr<mmodule->mod_end; addr+=PAGE_SIZE) {
page_set_mark(addr / PAGE_SIZE);
atomic_int32_inc(&total_allocated_pages);
atomic_int32_dec(&total_available_pages);
}
}
}

View file

@ -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

View file

@ -1,5 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#undef errno
extern int errno;

23
tools/Makefile Normal file
View file

@ -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

81
tools/make_initrd.c Normal file
View file

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
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;
}