From 7d5a38ada35ac196919c26675f211adb995b84ae Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Fri, 18 May 2012 14:47:44 +0200 Subject: Added initrd. Status: VFS support, totally useless shell. --- Makefile | 5 ++- menu_cdrom.lst | 1 + src/kernel/Makefile | 2 +- src/kernel/core/kmain.cpp | 23 ++++++++-- src/kernel/lib/std.cpp | 2 +- src/kernel/vfs/initrd.cpp | 67 ++++++++++++++++++++++++++++ src/kernel/vfs/initrd.h | 22 ++++++++++ src/kernel/vfs/vdir.cpp | 4 ++ src/kernel/vfs/vdir.h | 2 +- src/kernel/vfs/vfile.cpp | 34 ++++++++++++++ src/kernel/vfs/vfile.h | 23 ++++++++++ src/tools/makeinitrd/Makefile | 30 +++++++++++++ src/tools/makeinitrd/main.cpp | 95 ++++++++++++++++++++++++++++++++++++++++ src/tools/makeinitrd/makeinitrd | Bin 0 -> 16457 bytes 14 files changed, 302 insertions(+), 8 deletions(-) create mode 100644 src/kernel/vfs/initrd.cpp create mode 100644 src/kernel/vfs/initrd.h create mode 100644 src/kernel/vfs/vfile.cpp create mode 100644 src/kernel/vfs/vfile.h create mode 100644 src/tools/makeinitrd/Makefile create mode 100644 src/tools/makeinitrd/main.cpp create mode 100755 src/tools/makeinitrd/makeinitrd diff --git a/Makefile b/Makefile index 29ae6c3..ab689c0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: clean, mrproper, Init.rfs, floppy, commit -Projects = kernel user/lib user/test +Projects = tools/makeinitrd kernel user/lib user/test QemuCmd = qemu-system-i386 BasePath = $(shell pwd) @@ -42,6 +42,9 @@ $(Cdrom): menu_cdrom.lst src/kernel/kernel.elf src/user/test/test.elf echo "Please copy grub's stage2_eltorito to cdrom/boot/grub."; \ exit -1; \ fi + src/tools/makeinitrd/makeinitrd cdrom/initrd \ + src/user/test/test.elf:/bin/test \ + README:/readme cp menu_cdrom.lst cdrom/boot/grub/menu.lst cp src/kernel/kernel.elf cdrom cp src/user/test/test.elf cdrom diff --git a/menu_cdrom.lst b/menu_cdrom.lst index 4bbe812..1b99614 100644 --- a/menu_cdrom.lst +++ b/menu_cdrom.lst @@ -3,3 +3,4 @@ timeout 10 title T/CE kernel /kernel.elf module /test.elf +module /initrd diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 5c09e80..a6ad58a 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -4,7 +4,7 @@ Obj = core/loader_.o core/kmain.o core/sys.o \ lib/bitset.o lib/std.o lib/cpp.o lib/sched.o \ mem/mem.o mem/paging.o mem/gdt.o mem/_dlmalloc.o mem/seg.o \ linker/elf.o \ - vfs/node.o vfs/vdir.o \ + vfs/node.o vfs/vdir.o vfs/vfile.o vfs/initrd.o \ dev/vgatxt.o dev/keyboard.o dev/ps2keyboard.o \ ui/vt.o diff --git a/src/kernel/core/kmain.cpp b/src/kernel/core/kmain.cpp index 9ec06df..58a3c48 100644 --- a/src/kernel/core/kmain.cpp +++ b/src/kernel/core/kmain.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -76,16 +77,30 @@ extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) { // Load modules *ke_vt << "Loading modules :\n"; for (unsigned i = 0; i < mbd->mods_count; i++) { - *ke_vt << " * " << (char*)mods[i].string; + char* cmd = (char*)mods[i].string; + *ke_vt << " * " << cmd << " \t"; if (elf_check((uint8_t*)mods[i].mod_start) == 0) { process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER); if (pr == 0) { - *ke_vt << " : Error loading\n"; + *ke_vt << "Error loading\n"; } else { - *ke_vt << " : OK, pid=" << (int)pr->pid << "\n"; + *ke_vt << "OK, pid=" << (int)pr->pid << "\n"; + } + } else if (initrd_check((uint8_t*)mods[i].mod_start) == 0) { + vdir* fs = new vdir(root); + int e = initrd_load((uint8_t*)mods[i].mod_start, fs); + if (e == 0) { + char* name = cmd; + for (char* i = name; *i != 0; i++) { + if (*i == '/' || *i == ' ') name = i + 1; + } + root->add_child(name, fs); + *ke_vt << "OK, initrd as /" << name << "/\n"; + } else { + *ke_vt << "initrd but error " << e << "\n"; } } else { - *ke_vt << " : Invalid ELF file\n"; + *ke_vt << "Invalid file, neither ELF nor initrd.\n"; } } diff --git a/src/kernel/lib/std.cpp b/src/kernel/lib/std.cpp index 4407f55..c25f59c 100644 --- a/src/kernel/lib/std.cpp +++ b/src/kernel/lib/std.cpp @@ -16,7 +16,7 @@ void abort() { int strlen(const char *str) { int i = 0; while (str[i++]); - return i; + return i-1; } char *strchr(const char *str, char c) { diff --git a/src/kernel/vfs/initrd.cpp b/src/kernel/vfs/initrd.cpp new file mode 100644 index 0000000..50aa95c --- /dev/null +++ b/src/kernel/vfs/initrd.cpp @@ -0,0 +1,67 @@ +#include "initrd.h" +#include "vfile.h" +#include + +int initrd_check(uint8_t *data) { + initrd_header *h = (initrd_header*)data; + if (h->magic == INITRD_MAGIC) return 0; + return -1; +} + +int initrd_load(uint8_t *data, vdir *root) { + if (root == 0) return -1; + + union { + uint8_t *c; + initrd_header *ih; + initrd_file_header *fh; + } curr; + curr.c = data; + + if (curr.ih->magic != INITRD_MAGIC) return -2; + + uint32_t files = curr.ih->files; curr.ih++; + for (unsigned i = 0; i < files; i++) { + initrd_file_header *h = curr.fh; + curr.fh++; + if (h->name_length == 0) continue; + char* path = (char*)curr.c; + curr.c += h->name_length + 1; + if (strlen(path) != (int)h->name_length) return -3; + + node* parent = root; + // parse filename + char *member = path; + while (*path != 0 && parent != 0) { + if (*path == '/') { + if (member == path) { + member++; + path++; + } else { + *path = 0; + path++; + node* n = parent->get_child(member); + if (n == 0) { + n = new vdir(parent); + parent->add_child(member, n); + } + parent = n; + member = path; + } + } else { + path++; + } + } + if (parent == 0) return -5; + if (member == path) return -6; // filename ended by '/', bad. + + // add file + if (h->file_length == 0) { + if (parent->add_child(member, new vdir(parent)) != 0) return -4; + } else { + if (parent->add_child(member, new vfile(parent, (char*)curr.c, h->file_length)) != 0) return -4; + curr.c += h->file_length; + } + } + return 0; +} diff --git a/src/kernel/vfs/initrd.h b/src/kernel/vfs/initrd.h new file mode 100644 index 0000000..0cabccf --- /dev/null +++ b/src/kernel/vfs/initrd.h @@ -0,0 +1,22 @@ +#ifndef DEF_VFS_INITRD_H +#define DEF_VFS_INITRD_H + +#include "node.h" +#include "vdir.h" + +struct initrd_header { + unsigned int magic; //For error checking + unsigned int files; +}; + +struct initrd_file_header { + unsigned int name_length; + unsigned int file_length; +}; + +#define INITRD_MAGIC 0x12379846 + +int initrd_check(uint8_t *data); // returns 0 if initrd file, -1 otherwise +int initrd_load(uint8_t *data, vdir *root); + +#endif diff --git a/src/kernel/vfs/vdir.cpp b/src/kernel/vfs/vdir.cpp index 299c0e7..00b67cb 100644 --- a/src/kernel/vfs/vdir.cpp +++ b/src/kernel/vfs/vdir.cpp @@ -10,6 +10,10 @@ vdir::vdir(node* parent) : node(parent, FT_DIR), children(8, 64) { } } +vdir::~vdir() { + //TODO : free children +} + node* vdir::get_child(char* name) { for (unsigned i = 0; i < child_count; i++) { vdir_child *c = children.at(i); diff --git a/src/kernel/vfs/vdir.h b/src/kernel/vfs/vdir.h index 7ac1b2a..366b3f1 100644 --- a/src/kernel/vfs/vdir.h +++ b/src/kernel/vfs/vdir.h @@ -20,7 +20,7 @@ class vdir : public node { public: vdir(node* parent); - virtual ~vdir() {} + virtual ~vdir(); virtual int read(size_t offset, size_t len, char* buffer); virtual int write(size_t offset, size_t len, char* buffer); // rename file diff --git a/src/kernel/vfs/vfile.cpp b/src/kernel/vfs/vfile.cpp new file mode 100644 index 0000000..ff57c9e --- /dev/null +++ b/src/kernel/vfs/vfile.cpp @@ -0,0 +1,34 @@ +#include "vfile.h" + +vfile::vfile(node* parent, char* d, size_t s) : node(parent, FT_FILE) { + size = 0; + own_data = false; + + data = d; + if (d != 0) size = s; +} + +vfile::~vfile() { + if (own_data) kfree(data); +} + +int vfile::read(size_t offset, size_t len, char* buffer) { + if (offset + len > size) len = size - offset; + memcpy(buffer, data + offset, len); + return len; +} + +int vfile::write(size_t offset, size_t len, char* buffer) { + size_t new_size = MAX(offset + len, size); + if (!own_data || new_size > size) { + char* new_data = (char*)kmalloc(new_size); + memcpy(new_data, data, size); + if (new_size > size) memset(new_data + size, 0, new_size - size); + if (own_data) kfree(data); + data = new_data; + size = new_size; + own_data = true; + } + memcpy(data + offset, buffer, len); + return len; +} diff --git a/src/kernel/vfs/vfile.h b/src/kernel/vfs/vfile.h new file mode 100644 index 0000000..9b68b68 --- /dev/null +++ b/src/kernel/vfs/vfile.h @@ -0,0 +1,23 @@ +#ifndef DEF_VFS_VFILE_H +#define DEF_VFS_VFILE_H + +#include +#include "node.h" + +class vfile : public node { + char *data; + size_t size; + bool own_data; // did WE malloc the content of data ? + + public: + vfile(node* parent, char* data = 0, size_t size = 0); + virtual ~vfile(); + + // TODO: handle open(TRUNC) + virtual int read(size_t offset, size_t len, char* buffer); + virtual int write(size_t offset, size_t len, char* buffer); + virtual size_t get_size() { return size; } + +}; + +#endif diff --git a/src/tools/makeinitrd/Makefile b/src/tools/makeinitrd/Makefile new file mode 100644 index 0000000..3ac993c --- /dev/null +++ b/src/tools/makeinitrd/Makefile @@ -0,0 +1,30 @@ +.PHONY: clean, mrproper + +CC = gcc +CXX = g++ +LD = gcc +LDFLAGS = -lstdc++ +CFLAGS = +CXXFLAGS = + +OutFile = makeinitrd +Objects = main.o + +all: $(OutFile) + +rebuild: mrproper all + +$(OutFile): $(Objects) + $(LD) -o $(OutFile) $(LDFLAGS) $^ + +%.o: %.c + $(CC) -c $< -o $@ $(CFLAGS) + +%.o: %.cpp + $(CXX) -c $< -o $@ $(CXXFLAGS) + +clean: + rm -rf *.o + +mrproper: clean + rm -rf $(OutFile) diff --git a/src/tools/makeinitrd/main.cpp b/src/tools/makeinitrd/main.cpp new file mode 100644 index 0000000..ea8966b --- /dev/null +++ b/src/tools/makeinitrd/main.cpp @@ -0,0 +1,95 @@ +#include +#include +#include + +using namespace std; + +struct ramfs_header { + unsigned int magic; //For error checking + unsigned int files; +}; + +struct ramfs_file_header { + unsigned int name_length; + unsigned int file_length; +}; + +#define INITRD_MAGIC 0x12379846 + +int main(int argc, char *argv[]) { + if (argc < 2) { + cerr << "Error : no output file specified." << endl; + cerr << "Usage : MakeRamFS [: [...] ]" << endl; + return 1; + } + + ofstream output(argv[1], ios::out | ios::binary); + + ramfs_header hdr; + hdr.magic = INITRD_MAGIC; + hdr.files = argc - 2; + + output.write((char*)&hdr, sizeof(ramfs_header)); + + for (int i = 2; i < argc; i++) { + string name(argv[i]); + string file; + while (!name.empty()) { + if (name[0] == ':') { + name = name.substr(1, name.size() - 1); + break; + } + file += name[0]; + name = name.substr(1, name.size() - 1); + } + + ramfs_file_header fhdr; + + if (file == "") { //This is a directory + fhdr.name_length = name.size(); + fhdr.file_length = 0; //File length of 0 means directory + output.write((char*)&fhdr, sizeof(ramfs_file_header)); + output << name; + output << '\0'; + continue; + } + + ifstream infile(file.c_str(), ios::in | ios::binary); + + if (!infile) { + fhdr.name_length = 0; //Name and length = 0 means invalid file + fhdr.file_length = 0; + output.write((char*)&fhdr, sizeof(ramfs_file_header)); + continue; + } + + fhdr.name_length = name.size(); + fhdr.file_length = 0; + while (!infile.eof()) { + char c; + infile.read(&c, 1); + fhdr.file_length++; + } + + infile.close(); infile.open(file.c_str(), ios::in | ios::binary); //Rewind file + + output.write((char*)&fhdr, sizeof(ramfs_file_header)); + + output << name; + output << '\0'; + + char *c = new char[fhdr.file_length]; + for (int i = 0; i < fhdr.file_length; i++) { + char ch; + infile.read(&ch, 1); + output.write(&ch, 1); + } + delete [] c; + + infile.close(); + } + + output.close(); + + return 0; +} diff --git a/src/tools/makeinitrd/makeinitrd b/src/tools/makeinitrd/makeinitrd new file mode 100755 index 0000000..afb042c Binary files /dev/null and b/src/tools/makeinitrd/makeinitrd differ -- cgit v1.2.3