/* * initrd.c * * Created on: Sep 1, 2011 * Author: Tiberiu */ #define LUXMAGIC 0xCC23AA90 #define OEMSTR "luxram" #include #include #include #include #include #include "initrd.h" /************************************** * DEVICE 'FAKE' READ ROUTINE * **************************************/ uint32 luxInitrdDevRead (uint32 UNUSED(offset), void* UNUSED(buffer)) { return LUXMAGIC; } /************************************** * OTHER USEFUL ROUTINES * **************************************/ // Navigates and returns the directory entry that contains the file/folder luxDirectoryEntry rootDirectoryEntry; luxDirectoryEntry* luxGetFile (string path, uint32 data) { luxHeader* head = (luxHeader*)data; uint32 end = strlen(path); uint32 start, next = 0; char* tmp; // Remove ending '/' (if any) if (path[end-1] == '/') --end; // Empty string? Return the root if (end == 0) { rootDirectoryEntry.De.Flags = 0xB68; // read & execute only rootDirectoryEntry.De.GroupId = 0; // system group rootDirectoryEntry.De.OwnerId = 0; // system owner rootDirectoryEntry.De.Size = sizeof(uint32) + head->RootSize * sizeof(luxDirectoryEntry); rootDirectoryEntry.Offset = (uint32)(&head->RootSize) - data; // calculate offset return &rootDirectoryEntry; } // Make sure path is correct if (path[0] != '/') return NULL; // Parse each directory until we find the one containing the file; uint32 cDir = (uint32)&head->RootSize; while (next < end) { // Parse string start = next + 1; // Skip path separator tmp = strchr(&path[start], '/'); // Find next separator next = (!tmp) ? end : (uint32)(tmp - path) ; // Mark end of string, or next dir position in path // strchr doesn't know when to end if (next >= end) { tmp = 0; next = end; } // Look for directory uint32 i, find = 0xffffffff; uint32 size = *(uint32*)cDir; luxDirectoryEntry* de = (luxDirectoryEntry*) (cDir + sizeof(uint32)); for (i = 0; i < size && find == 0xffffffff; i++) if (strncmp(de[i].De.Name, &path[start], strlen(de[i].De.Name)) == 0) find = i; // Not found? Nope, not good if (find == 0xffffffff) return NULL; // End of string? Return directory entry if (!tmp) return &de[find]; // make sure we don't try to read a file as a folder if ((de[find].De.Flags & 0x7) != FileDirectory) return NULL; // Not end of string? Continue cDir = (uint32) (data + de[find].Offset); } return NULL; } /************************************** * FILE SYSTEM INTERFACE ROUTINES * **************************************/ uint32 luxDetect (MountPoint* mp) { void* buffer = kmalloc(mp->BlockSize); // must allocate a buffer for non-initrd devices... uint32 result = mp->Read(0, buffer); // read something kfree(buffer); // get rid of the not needed buffer return (result == LUXMAGIC); // returned magic number? good } // Test if a file exists DirectoryEntry* luxTest (MountPoint* mp, string path) { // MountPoint.FsData[0] contains initrd image start address // luxDirectoryEntry contains a DirectoryEntry return (DirectoryEntry*) luxGetFile(path, mp->FsData[0]); // Get a directory and see } // Open a file FILE* luxOpen (MountPoint* mp, FILE* f, string path) { // Find it first. mp->FsData[0] contains initrd image start address. luxDirectoryEntry* entry = luxGetFile(path, mp->FsData[0]); // Invalid entry if (entry == NULL) return NULL; // Set some data fields f->Name = entry->De.Name; f->Flags = entry->De.Flags; f->GroupId = entry->De.GroupId; f->OwnerId = entry->De.OwnerId; f->Size = entry->De.Size; // Set up the buffer info. We will use these to read/write the file. f->BufStart = (void*) (mp->FsData[0] + entry->Offset); f->BufPos = f->BufStart; f->BufEnd = f->BufStart + entry->De.Size; // And return it return f; } // Close a file FILE* luxClose (MountPoint* UNUSED(mp), FILE* f) { // Just empty buffer info, so we don't attempt to read it again f->BufStart = f->BufPos = f->BufEnd = NULL; return f; } // Read data from a file // Returns byte count read uint32 luxRead (MountPoint* UNUSED(mp), FILE* f, uint32 elemsz, uint32 n, uint8* buffer) { // Make sure we don't read more than we can uint32 total = Min(elemsz * n, (uint32)f->BufEnd - (uint32)f->BufPos); memcpy(buffer, f->BufPos, total); // Copy data f->BufPos = (void*) ((uint32)f->BufPos + total); // Set new buffer position return total; // Return byte count read } // Read contents of a directory DirectoryEntry* luxReadDir (MountPoint* UNUSED(mp), FILE* f, uint32 index) { uint32 size = *(uint32*)f->BufStart; luxDirectoryEntry* de = (luxDirectoryEntry*) ((uint32)f->BufStart + sizeof(uint32)); if (index >= size) return NULL; return (DirectoryEntry*) &de[index]; } /************************************** * INITIALIZATION ROUTINE * **************************************/ void luxInitrdInstall (MultibootInfo* info) { uint32 i; MountPoint* mp; // Register file system FileSystem fs = {0, "luxinitrd", luxDetect, 0, 0, luxOpen, luxClose, luxRead, 0, luxTest, luxReadDir}; VfsInstallFs(&fs); // Check for multiboot info flags to see if any modules are loaded if ((info->Flags & 8) == 0) { Error("Initrd", "No boot modules found!"); return; } // Loop through each module and if it is an initrd image, mount it MultibootModule* modules = (MultibootModule*) info->ModulesAddress; for (i = 0; i < info->ModulesCount; i++) if (*((uint32*) modules[i].ModuleStart) == LUXMAGIC) { // Mount the device Log("Initrd", "Found initrd image at 0x%x.\n", modules[i].ModuleStart); mp = VfsMount("initrd", luxInitrdDevRead, NULL, 0x0); // Set up data fields mp->FsData[0] = modules[i].ModuleStart; mp->FsData[1] = modules[i].ModuleEnd; } else { Log("Initrd", "Found module @ 0x%x, but not initrd image.\n", modules[i].ModuleStart); } }