Add support for multiple initrds.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-11-04 14:06:17 +01:00
parent 391680a468
commit 475bd7c26e
6 changed files with 160 additions and 327 deletions

View File

@ -83,7 +83,6 @@ clock.o \
com.o \ com.o \
copy.o \ copy.o \
$(CPUDIR)/kthread.o \ $(CPUDIR)/kthread.o \
crc32.o \
debugger.o \ debugger.o \
descriptor.o \ descriptor.o \
disk/ahci/ahci.o \ disk/ahci/ahci.o \

View File

@ -1,72 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Krzysztof Dabrowski 1999, 2000.
Copyright(C) ElysiuM deeZine 1999, 2000.
Based on implementation by Finn Yannick Jacobs.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
crc32.cpp
Calculates a CRC32 Checksum of binary data.
*******************************************************************************/
#include <sortix/kernel/crc32.h>
#include <sortix/kernel/kernel.h>
namespace Sortix {
namespace CRC32 {
void GenerateTable(uint32_t tabel[256])
{
uint32_t poly = 0xEDB88320U;
for ( uint32_t i = 0; i < 256; i++ )
{
uint32_t crc = i;
for ( uint32_t j = 8; 0 < j; j-- )
{
if ( crc & 1 ) { crc = (crc >> 1) ^ poly; }
else { crc >>= 1; }
}
tabel[i] = crc;
}
}
uint32_t Continue(uint32_t tabel[256], uint32_t crc, uint8_t* block,
size_t size)
{
for ( size_t i = 0; i < size; i++ )
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ tabel[(crc ^ *block++) & 0xFF];
}
return crc;
}
uint32_t Finish(uint32_t crc)
{
return crc ^ 0xFFFFFFFF;
}
uint32_t Hash(uint8_t* block, size_t size)
{
uint32_t tabel[256];
GenerateTable(tabel);
return Finish(Continue(tabel, START_SEED, block, size));
}
} // namespace CRC32
} // namespace Sortix

View File

@ -1,46 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Krzysztof Dabrowski 1999, 2000.
Copyright(C) ElysiuM deeZine 1999, 2000.
Based on implementation by Finn Yannick Jacobs.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
sortix/kernel/crc32.h
Calculates a CRC32 Checksum of binary data.
*******************************************************************************/
#ifndef SORTIX_CRC32_H
#define SORTIX_CRC32_H
#include <stddef.h>
#include <stdint.h>
namespace Sortix {
namespace CRC32 {
const uint32_t START_SEED = 0xFFFFFFFF;
void GenerateTable(uint32_t tabel[256]);
uint32_t Continue(uint32_t tabel[256], uint32_t crc, uint8_t* buf, size_t size);
uint32_t Finish(uint32_t crc);
uint32_t Hash(uint8_t* block, size_t size);
} // namespace CRC32
} // namespace Sortix
#endif

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This file is part of Sortix. This file is part of Sortix.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>. Sortix. If not, see <http://www.gnu.org/licenses/>.
initrd.cpp initrd.cpp
Extracts the initrd into the initial memory filesystem. Extracts initrds into the initial memory filesystem.
*******************************************************************************/ *******************************************************************************/
@ -39,7 +39,6 @@
#include <sortix/stat.h> #include <sortix/stat.h>
#include <sortix/kernel/addralloc.h> #include <sortix/kernel/addralloc.h>
#include <sortix/kernel/crc32.h>
#include <sortix/kernel/descriptor.h> #include <sortix/kernel/descriptor.h>
#include <sortix/kernel/fsfunc.h> #include <sortix/kernel/fsfunc.h>
#include <sortix/kernel/ioctx.h> #include <sortix/kernel/ioctx.h>
@ -50,9 +49,9 @@
#include <sortix/kernel/vnode.h> #include <sortix/kernel/vnode.h>
#include "initrd.h" #include "initrd.h"
#include "multiboot.h"
namespace Sortix { namespace Sortix {
namespace InitRD {
// TODO: The initrd is not being properly verified. // TODO: The initrd is not being properly verified.
// TODO: The initrd is not handled in an endian-neutral manner. // TODO: The initrd is not handled in an endian-neutral manner.
@ -61,44 +60,27 @@ struct initrd_context
{ {
uint8_t* initrd; uint8_t* initrd;
size_t initrd_size; size_t initrd_size;
size_t amount_extracted; addr_t initrd_unmap_start;
initrd_superblock_t* sb; addr_t initrd_unmap_end;
struct initrd_superblock* sb;
Ref<Descriptor> links; Ref<Descriptor> links;
ioctx_t ioctx; ioctx_t ioctx;
int last_percent;
}; };
void initrd_activity(const char* status, const char* format, ...) // TODO: GRUB is currently buggy and doesn't ensure that other things are placed
// at the end of a module, i.e. that the module doesn't own all the bugs
// that it spans. It's thus risky to actually recycle the last page if the
// module doesn't use all of it. Remove this compatibility when this has
// been fixed in GRUB and a few years have passed such that most GRUB
// systems have this fixed.
static void UnmapInitrdPage(struct initrd_context* ctx, addr_t vaddr)
{ {
Log::PrintF("\r"); if ( !Memory::LookUp(vaddr, NULL, NULL) )
Log::PrintF(" [%6.6s] ", status);
va_list ap;
va_start(ap, format);
Log::PrintFV(format, ap);
va_end(ap);
Log::PrintF("...");
size_t column, row;
while ( Log::GetCursor(&column, &row), column != Log::Width() )
Log::PrintF(" ");
Log::PrintF("\e[0J");
}
void initrd_activity_done()
{
Log::PrintF("\r\e[0J");
}
void initrd_progress(struct initrd_context* ctx)
{
int percent = 100;
if ( ctx->initrd_size && ctx->initrd_size != ctx->amount_extracted )
percent = ((uint64_t) ctx->amount_extracted * 100) / ctx->initrd_size;
if ( percent == ctx->last_percent )
return; return;
char status[6 + 1]; addr_t addr = Memory::Unmap(vaddr);
snprintf(status, sizeof(status), " %3i%% ", percent); if ( !(ctx->initrd_unmap_start <= addr && addr < ctx->initrd_unmap_end) )
initrd_activity(status, "Extracting ramdisk into initial filesystem"); return;
ctx->last_percent = percent; Page::Put(addr, PAGE_USAGE_WASNT_ALLOCATED);
} }
static mode_t initrd_mode_to_host_mode(uint32_t mode) static mode_t initrd_mode_to_host_mode(uint32_t mode)
@ -115,20 +97,25 @@ static mode_t initrd_mode_to_host_mode(uint32_t mode)
return result; return result;
} }
static initrd_inode_t* initrd_get_inode(struct initrd_context* ctx, uint32_t inode) static struct initrd_inode* initrd_get_inode(struct initrd_context* ctx,
uint32_t inode)
{ {
if ( ctx->sb->inodecount <= inode ) if ( ctx->sb->inodecount <= inode )
return errno = EINVAL, (initrd_inode_t*) NULL; return errno = EINVAL, (struct initrd_inode*) NULL;
uint32_t pos = ctx->sb->inodeoffset + ctx->sb->inodesize * inode; uint32_t pos = ctx->sb->inodeoffset + ctx->sb->inodesize * inode;
return (initrd_inode_t*) (ctx->initrd + pos); return (struct initrd_inode*) (ctx->initrd + pos);
} }
static uint8_t* initrd_inode_get_data(struct initrd_context* ctx, initrd_inode_t* inode, size_t* size) static uint8_t* initrd_inode_get_data(struct initrd_context* ctx,
struct initrd_inode* inode,
size_t* size)
{ {
return *size = inode->size, ctx->initrd + inode->dataoffset; return *size = inode->size, ctx->initrd + inode->dataoffset;
} }
static uint32_t initrd_directory_open(struct initrd_context* ctx, initrd_inode_t* inode, const char* name) static uint32_t initrd_directory_open(struct initrd_context* ctx,
struct initrd_inode* inode,
const char* name)
{ {
if ( !INITRD_S_ISDIR(inode->mode) ) if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, 0; return errno = ENOTDIR, 0;
@ -136,7 +123,8 @@ static uint32_t initrd_directory_open(struct initrd_context* ctx, initrd_inode_t
while ( offset < inode->size ) while ( offset < inode->size )
{ {
uint32_t pos = inode->dataoffset + offset; uint32_t pos = inode->dataoffset + offset;
initrd_dirent* dirent = (initrd_dirent*) (ctx->initrd + pos); struct initrd_dirent* dirent =
(struct initrd_dirent*) (ctx->initrd + pos);
if ( dirent->namelen && !strcmp(dirent->name, name) ) if ( dirent->namelen && !strcmp(dirent->name, name) )
return dirent->inode; return dirent->inode;
offset += dirent->reclen; offset += dirent->reclen;
@ -144,7 +132,9 @@ static uint32_t initrd_directory_open(struct initrd_context* ctx, initrd_inode_t
return errno = ENOENT, 0; return errno = ENOENT, 0;
} }
static const char* initrd_directory_get_filename(struct initrd_context* ctx, initrd_inode_t* inode, size_t index) static const char* initrd_directory_get_filename(struct initrd_context* ctx,
struct initrd_inode* inode,
size_t index)
{ {
if ( !INITRD_S_ISDIR(inode->mode) ) if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, (const char*) NULL; return errno = ENOTDIR, (const char*) NULL;
@ -152,7 +142,8 @@ static const char* initrd_directory_get_filename(struct initrd_context* ctx, ini
while ( offset < inode->size ) while ( offset < inode->size )
{ {
uint32_t pos = inode->dataoffset + offset; uint32_t pos = inode->dataoffset + offset;
initrd_dirent* dirent = (initrd_dirent*) (ctx->initrd + pos); struct initrd_dirent* dirent =
(struct initrd_dirent*) (ctx->initrd + pos);
if ( index-- == 0 ) if ( index-- == 0 )
return dirent->name; return dirent->name;
offset += dirent->reclen; offset += dirent->reclen;
@ -160,7 +151,8 @@ static const char* initrd_directory_get_filename(struct initrd_context* ctx, ini
return errno = EINVAL, (const char*) NULL; return errno = EINVAL, (const char*) NULL;
} }
static size_t initrd_directory_get_num_files(struct initrd_context* ctx, initrd_inode_t* inode) static size_t initrd_directory_get_num_files(struct initrd_context* ctx,
struct initrd_inode* inode)
{ {
if ( !INITRD_S_ISDIR(inode->mode) ) if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, 0; return errno = ENOTDIR, 0;
@ -169,23 +161,26 @@ static size_t initrd_directory_get_num_files(struct initrd_context* ctx, initrd_
while ( offset < inode->size ) while ( offset < inode->size )
{ {
uint32_t pos = inode->dataoffset + offset; uint32_t pos = inode->dataoffset + offset;
const initrd_dirent* dirent = (const initrd_dirent*) (ctx->initrd + pos); const struct initrd_dirent* dirent =
(const struct initrd_dirent*) (ctx->initrd + pos);
numentries++; numentries++;
offset += dirent->reclen; offset += dirent->reclen;
} }
return numentries; return numentries;
} }
static bool ExtractNode(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> node); static void ExtractNode(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> node);
static bool ExtractFile(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> file) static void ExtractFile(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> file)
{ {
size_t filesize; size_t filesize;
uint8_t* data = initrd_inode_get_data(ctx, inode, &filesize); uint8_t* data = initrd_inode_get_data(ctx, inode, &filesize);
if ( !data )
return false;
if ( file->truncate(&ctx->ioctx, filesize) != 0 ) if ( file->truncate(&ctx->ioctx, filesize) != 0 )
return false; PanicF("initrd: truncate: %m");
size_t sofar = 0; size_t sofar = 0;
while ( sofar < filesize ) while ( sofar < filesize )
{ {
@ -194,68 +189,71 @@ static bool ExtractFile(struct initrd_context* ctx, initrd_inode_t* inode, Ref<D
size_t count = left < chunk ? left : chunk; size_t count = left < chunk ? left : chunk;
ssize_t numbytes = file->write(&ctx->ioctx, data + sofar, count); ssize_t numbytes = file->write(&ctx->ioctx, data + sofar, count);
if ( numbytes <= 0 ) if ( numbytes <= 0 )
return false; PanicF("initrd: write: %m");
sofar += numbytes; sofar += numbytes;
ctx->amount_extracted += numbytes;
initrd_progress(ctx);
} }
return true;
} }
static bool ExtractDir(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> dir) static void ExtractDir(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> dir)
{ {
size_t numfiles = initrd_directory_get_num_files(ctx, inode); size_t numfiles = initrd_directory_get_num_files(ctx, inode);
for ( size_t i = 0; i < numfiles; i++ ) for ( size_t i = 0; i < numfiles; i++ )
{ {
const char* name = initrd_directory_get_filename(ctx, inode, i); const char* name = initrd_directory_get_filename(ctx, inode, i);
if ( !name ) if ( !name )
return false; PanicF("initrd_directory_get_filename: %m");
if ( IsDotOrDotDot(name) ) if ( IsDotOrDotDot(name) )
continue; continue;
uint32_t childino = initrd_directory_open(ctx, inode, name); uint32_t childino = initrd_directory_open(ctx, inode, name);
if ( !childino ) if ( !childino )
return false; PanicF("initrd_directory_open: %s: %m", name);
initrd_inode_t* child = (initrd_inode_t*) initrd_get_inode(ctx, childino); struct initrd_inode* child =
(struct initrd_inode*) initrd_get_inode(ctx, childino);
mode_t mode = initrd_mode_to_host_mode(child->mode); mode_t mode = initrd_mode_to_host_mode(child->mode);
if ( INITRD_S_ISDIR(child->mode) ) if ( INITRD_S_ISDIR(child->mode) )
{ {
if ( dir->mkdir(&ctx->ioctx, name, mode) && errno != EEXIST ) if ( dir->mkdir(&ctx->ioctx, name, mode) && errno != EEXIST )
return false; PanicF("initrd: mkdir: %s: %m", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_SEARCH | O_DIRECTORY, 0); Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_SEARCH | O_DIRECTORY, 0);
if ( !desc ) if ( !desc )
return false; PanicF("initrd: %s: %m", name);
if ( !ExtractNode(ctx, child, desc) ) ExtractNode(ctx, child, desc);
return false;
} }
if ( INITRD_S_ISREG(child->mode) ) if ( INITRD_S_ISREG(child->mode) )
{ {
assert(child->nlink != 0); assert(child->nlink != 0);
char link_path[sizeof(childino) * 3]; char link_path[sizeof(childino) * 3];
snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino); snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino);
Ref<Descriptor> existing(ctx->links->open(&ctx->ioctx, link_path, O_READ, 0)); Ref<Descriptor> existing(ctx->links->open(&ctx->ioctx, link_path,
O_READ, 0));
if ( !existing || dir->link(&ctx->ioctx, name, existing) != 0 ) if ( !existing || dir->link(&ctx->ioctx, name, existing) != 0 )
{ {
Ref<Descriptor> desc(dir->open(&ctx->ioctx, name, O_WRITE | O_CREATE, mode)); Ref<Descriptor> desc(dir->open(&ctx->ioctx, name,
O_WRITE | O_CREATE, mode));
if ( !desc ) if ( !desc )
return false; PanicF("initrd: %s: %m", name);
if ( !ExtractNode(ctx, child, desc) ) ExtractNode(ctx, child, desc);
return false;
if ( 2 <= child->nlink ) if ( 2 <= child->nlink )
ctx->links->link(&ctx->ioctx, link_path, desc); ctx->links->link(&ctx->ioctx, link_path, desc);
} }
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) ) if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
{ {
size_t filesize; size_t filesize;
const uint8_t* data = initrd_inode_get_data(ctx, child, &filesize); const uint8_t* data =
initrd_inode_get_data(ctx, child, &filesize);
uintptr_t from = (uintptr_t) data; uintptr_t from = (uintptr_t) data;
uintptr_t size = filesize; uintptr_t size = filesize;
uintptr_t from_aligned = Page::AlignUp(from); uintptr_t from_aligned = Page::AlignUp(from);
uintptr_t from_distance = from_aligned - from; uintptr_t from_distance = from_aligned - from;
if ( from_distance <= size ) if ( from_distance <= size )
{ {
uintptr_t size_aligned = Page::AlignDown(size - from_distance); uintptr_t size_aligned =
Page::AlignDown(size - from_distance);
for ( size_t i = 0; i < size_aligned; i += Page::Size() ) for ( size_t i = 0; i < size_aligned; i += Page::Size() )
Page::Put(Memory::Unmap(from_aligned + i), PAGE_USAGE_WASNT_ALLOCATED); UnmapInitrdPage(ctx, from_aligned + i);
Memory::Flush(); Memory::Flush();
} }
} }
@ -264,122 +262,56 @@ static bool ExtractDir(struct initrd_context* ctx, initrd_inode_t* inode, Ref<De
{ {
size_t filesize; size_t filesize;
uint8_t* data = initrd_inode_get_data(ctx, child, &filesize); uint8_t* data = initrd_inode_get_data(ctx, child, &filesize);
if ( !data )
return false;
char* oldname = new char[filesize + 1]; char* oldname = new char[filesize + 1];
if ( !oldname )
PanicF("initrd: malloc: %m");
memcpy(oldname, data, filesize); memcpy(oldname, data, filesize);
oldname[filesize] = '\0'; oldname[filesize] = '\0';
int ret = dir->symlink(&ctx->ioctx, oldname, name); int ret = dir->symlink(&ctx->ioctx, oldname, name);
delete[] oldname; delete[] oldname;
if ( ret < 0 ) if ( ret < 0 )
return false; PanicF("initrd: symlink: %s", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_READ | O_SYMLINK_NOFOLLOW, 0); Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_READ | O_SYMLINK_NOFOLLOW, 0);
if ( desc ) if ( desc )
ExtractNode(ctx, child, desc); ExtractNode(ctx, child, desc);
ctx->amount_extracted += child->size;
initrd_progress(ctx);
} }
} }
ctx->amount_extracted += inode->size;
initrd_progress(ctx);
return true;
} }
static bool ExtractNode(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> node) static void ExtractNode(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> node)
{ {
if ( node->chmod(&ctx->ioctx, initrd_mode_to_host_mode(inode->mode)) < 0 ) if ( node->chmod(&ctx->ioctx, initrd_mode_to_host_mode(inode->mode)) < 0 )
return false; PanicF("initrd: chmod: %m");
if ( node->chown(&ctx->ioctx, inode->uid, inode->gid) < 0 ) if ( node->chown(&ctx->ioctx, inode->uid, inode->gid) < 0 )
return false; PanicF("initrd: chown: %m");
if ( INITRD_S_ISDIR(inode->mode) ) if ( INITRD_S_ISDIR(inode->mode) )
if ( !ExtractDir(ctx, inode, node) ) ExtractDir(ctx, inode, node);
return false;
if ( INITRD_S_ISREG(inode->mode) ) if ( INITRD_S_ISREG(inode->mode) )
if ( !ExtractFile(ctx, inode, node) ) ExtractFile(ctx, inode, node);
return false;
struct timespec ctime = timespec_make((time_t) inode->ctime, 0); struct timespec ctime = timespec_make((time_t) inode->ctime, 0);
struct timespec mtime = timespec_make((time_t) inode->mtime, 0); struct timespec mtime = timespec_make((time_t) inode->mtime, 0);
if ( node->utimens(&ctx->ioctx, &mtime, &ctime, &mtime) < 0 ) if ( node->utimens(&ctx->ioctx, &mtime, &ctime, &mtime) < 0 )
return false; PanicF("initrd: utimens: %m");
return true;
} }
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc) static void ExtractInitrd(Ref<Descriptor> desc, struct initrd_context* ctx)
{ {
initrd_activity(" ", "Verifying ramdisk checksum"); ctx->sb = (struct initrd_superblock*) ctx->initrd;
// Allocate the needed kernel virtual address space. if ( ctx->initrd_size < ctx->sb->fssize )
addralloc_t initrd_addr_alloc; Panic("Initrd header does not match its size");
if ( !AllocateKernelAddress(&initrd_addr_alloc, size) )
PanicF("Can't allocate 0x%zx bytes of kernel address space for the "
"init ramdisk", size );
// Map the physical frames onto our address space. if ( desc->mkdir(&ctx->ioctx, ".initrd-links", 0777) != 0 )
addr_t mapat = initrd_addr_alloc.from; PanicF("initrd: .initrd-links: %m");
for ( size_t i = 0; i < size; i += Page::Size() )
if ( !Memory::Map(physaddr + i, mapat + i, PROT_KREAD | PROT_KWRITE) )
PanicF("Unable to map the init ramdisk into virtual memory");
Memory::Flush();
struct initrd_context ctx; if ( !(ctx->links = desc->open(&ctx->ioctx, ".initrd-links",
memset(&ctx, 0, sizeof(ctx)); O_READ | O_DIRECTORY, 0)) )
ctx.initrd = (uint8_t*) mapat; PanicF("initrd: .initrd-links: %m");
ctx.initrd_size = size;
ctx.amount_extracted = 0;
ctx.last_percent = -1;
SetupKernelIOCtx(&ctx.ioctx);
if ( size < sizeof(*ctx.sb) ) ExtractNode(ctx, initrd_get_inode(ctx, ctx->sb->root), desc);
PanicF("initrd is too small");
ctx.sb = (initrd_superblock_t*) ctx.initrd;
if ( !String::StartsWith(ctx.sb->magic, "sortix-initrd") )
PanicF("Invalid magic value in initrd. This means the ramdisk may have "
"been corrupted by the bootloader, or that an incompatible file "
"has been passed to the kernel.");
if ( strcmp(ctx.sb->magic, "sortix-initrd-1") == 0 )
PanicF("Sortix initrd format version 1 is no longer supported.");
if ( strcmp(ctx.sb->magic, "sortix-initrd-2") != 0 )
PanicF("The initrd has a format that isn't supported. Perhaps it is "
"too new? Try downgrade or regenerate the initrd.");
if ( size < ctx.sb->fssize )
PanicF("The initrd said it is %u bytes, but the kernel was only passed "
"%zu bytes by the bootloader, which is not enough.",
ctx.sb->fssize, size);
uint32_t amount = ctx.sb->fssize - ctx.sb->sumsize;
uint8_t* filesum = ctx.initrd + amount;
if ( ctx.sb->sumalgorithm != INITRD_ALGO_CRC32 )
{
Log::PrintF("Warning: InitRD checksum algorithm not supported\n");
}
else
{
uint32_t crc32 = *((uint32_t*) filesum);
uint32_t filecrc32 = CRC32::Hash(ctx.initrd, amount);
if ( crc32 != filecrc32 )
{
PanicF("InitRD had checksum %X, expected %X: this means the ramdisk "
"may have been corrupted by the bootloader.", filecrc32, crc32);
}
}
initrd_activity(" OK ", "Verifying ramdisk checksum");
initrd_progress(&ctx);
if ( desc->mkdir(&ctx.ioctx, ".initrd-links", 0777) != 0 )
return false;
if ( !(ctx.links = desc->open(&ctx.ioctx, ".initrd-links", O_READ | O_DIRECTORY, 0)) )
return false;
if ( !ExtractNode(&ctx, initrd_get_inode(&ctx, ctx.sb->root), desc) )
return false;
union union
{ {
@ -387,38 +319,75 @@ bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
uint8_t dirent_data[sizeof(struct dirent) + sizeof(uintmax_t) * 3]; uint8_t dirent_data[sizeof(struct dirent) + sizeof(uintmax_t) * 3];
}; };
while ( 0 < ctx.links->readdirents(&ctx.ioctx, &dirent, sizeof(dirent_data)) && while ( 0 < ctx->links->readdirents(&ctx->ioctx, &dirent, sizeof(dirent_data)) &&
((const char*) dirent.d_name)[0] ) ((const char*) dirent.d_name)[0] )
{ {
if ( ((const char*) dirent.d_name)[0] == '.' ) if ( ((const char*) dirent.d_name)[0] == '.' )
continue; continue;
ctx.links->unlinkat(&ctx.ioctx, dirent.d_name, AT_REMOVEFILE); ctx->links->unlinkat(&ctx->ioctx, dirent.d_name, AT_REMOVEFILE);
ctx.links->lseek(&ctx.ioctx, 0, SEEK_SET); ctx->links->lseek(&ctx->ioctx, 0, SEEK_SET);
} }
ctx.links.Reset(); ctx->links.Reset();
desc->unlinkat(&ctx.ioctx, ".initrd-links", AT_REMOVEDIR); desc->unlinkat(&ctx->ioctx, ".initrd-links", AT_REMOVEDIR);
}
// Unmap the pages and return the physical frames for reallocation. static void ExtractModule(struct multiboot_mod_list* module,
for ( size_t i = 0; i < initrd_addr_alloc.size; i += Page::Size() ) Ref<Descriptor> desc,
struct initrd_context* ctx)
{
size_t mod_size = module->mod_end - module->mod_start;
// Allocate the needed kernel virtual address space.
addralloc_t initrd_addr_alloc;
if ( !AllocateKernelAddress(&initrd_addr_alloc, mod_size) )
PanicF("Failed to allocate kernel address space for the initrd");
// Map the physical frames onto our address space.
addr_t physfrom = module->mod_start;
addr_t mapat = initrd_addr_alloc.from;
for ( size_t i = 0; i < mod_size; i += Page::Size() )
{ {
if ( !Memory::LookUp(mapat + i, NULL, NULL) ) if ( !Memory::Map(physfrom + i, mapat + i, PROT_KREAD | PROT_KWRITE) )
continue; PanicF("Unable to map the initrd into virtual memory");
addr_t addr = Memory::Unmap(mapat + i);
Page::Put(addr, PAGE_USAGE_WASNT_ALLOCATED);
} }
Memory::Flush(); Memory::Flush();
ctx->initrd = (uint8_t*) initrd_addr_alloc.from;
ctx->initrd_size = mod_size;
ctx->initrd_unmap_start = module->mod_start;
ctx->initrd_unmap_end = Page::AlignDown(module->mod_end);
if ( sizeof(struct initrd_superblock) <= ctx->initrd_size &&
!memcmp(ctx->initrd, "sortix-initrd-2", strlen("sortix-initrd-2")) )
{
ExtractInitrd(desc, ctx);
}
else
{
Panic("Unsupported initrd format");
}
// Unmap the pages and return the physical frames for reallocation.
for ( size_t i = 0; i < mod_size; i += Page::Size() )
UnmapInitrdPage(ctx, mapat + i);
Memory::Flush();
// Free the used virtual address space. // Free the used virtual address space.
FreeKernelAddress(&initrd_addr_alloc); FreeKernelAddress(&initrd_addr_alloc);
ctx.amount_extracted = ctx.initrd_size;
initrd_progress(&ctx);
initrd_activity_done();
return true;
} }
} // namespace InitRD void ExtractModules(struct multiboot_info* bootinfo, Ref<Descriptor> root)
{
struct multiboot_mod_list* modules =
(struct multiboot_mod_list*) (uintptr_t) bootinfo->mods_addr;
struct initrd_context ctx;
memset(&ctx, 0, sizeof(ctx));
SetupKernelIOCtx(&ctx.ioctx);
for ( uint32_t i = 0; i < bootinfo->mods_count; i++ )
ExtractModule(&modules[i], root, &ctx);
}
} // namespace Sortix } // namespace Sortix

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This file is part of Sortix. This file is part of Sortix.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>. Sortix. If not, see <http://www.gnu.org/licenses/>.
initrd.h initrd.h
Provides low-level access to a Sortix init ramdisk. Extracts initrds into the initial memory filesystem.
*******************************************************************************/ *******************************************************************************/
@ -27,15 +27,13 @@
#include <sortix/kernel/refcount.h> #include <sortix/kernel/refcount.h>
struct multiboot_info;
namespace Sortix { namespace Sortix {
class Descriptor; class Descriptor;
namespace InitRD { void ExtractModules(struct multiboot_info* bootinfo, Ref<Descriptor> root);
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc);
} // namespace InitRD
} // namespace Sortix } // namespace Sortix

View File

@ -111,8 +111,7 @@ static void BootThread(void* user);
static void InitThread(void* user); static void InitThread(void* user);
static void SystemIdleThread(void* user); static void SystemIdleThread(void* user);
addr_t initrd; static multiboot_info_t* bootinfo;
size_t initrdsize;
static char* init_cmdline; static char* init_cmdline;
static char* cmdline_tokenize(char** saved) static char* cmdline_tokenize(char** saved)
@ -160,9 +159,10 @@ static char* cmdline_tokenize(char** saved)
return data; return data;
} }
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
{ {
(void) magic; (void) magic;
bootinfo = bootinfo_p;
// //
// Stage 1. Initialization of Early Environment. // Stage 1. Initialization of Early Environment.
@ -286,20 +286,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
init_cmdline = parameter; init_cmdline = parameter;
} }
initrd = 0;
initrdsize = 0;
uint32_t* modules = (uint32_t*) (addr_t) bootinfo->mods_addr;
for ( uint32_t i = 0; i < bootinfo->mods_count; i++ )
{
initrdsize = modules[2*i+1] - modules[2*i+0];
initrd = (addr_t) modules[2*i+0];
break;
}
if ( !initrd )
Panic("No init ramdisk provided");
// Initialize the interrupt handler table and enable interrupts. // Initialize the interrupt handler table and enable interrupts.
Interrupt::Init(); Interrupt::Init();
@ -436,11 +422,10 @@ static void BootThread(void* /*user*/)
if ( iroot->link_raw(&ctx, "..", iroot) != 0 ) if ( iroot->link_raw(&ctx, "..", iroot) != 0 )
Panic("Unable to link /.. to /"); Panic("Unable to link /.. to /");
// Install the initrd into our fresh RAM filesystem. // Extract the initrds.
if ( !InitRD::ExtractFromPhysicalInto(initrd, initrdsize, droot) ) if ( bootinfo->mods_count == 0 )
Panic("Unable to extract initrd into RAM root filesystem. Your machine " Panic("No initrd was loaded");
"needs more memory to boot using this initrd, as a rule of thumb " ExtractModules(bootinfo, droot);
"you need twice as much memory as the size of the initrd device.");
// //
// Stage 5. Loading and Initializing Core Drivers. // Stage 5. Loading and Initializing Core Drivers.