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 \
copy.o \
$(CPUDIR)/kthread.o \
crc32.o \
debugger.o \
descriptor.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.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>.
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/kernel/addralloc.h>
#include <sortix/kernel/crc32.h>
#include <sortix/kernel/descriptor.h>
#include <sortix/kernel/fsfunc.h>
#include <sortix/kernel/ioctx.h>
@ -50,9 +49,9 @@
#include <sortix/kernel/vnode.h>
#include "initrd.h"
#include "multiboot.h"
namespace Sortix {
namespace InitRD {
// TODO: The initrd is not being properly verified.
// TODO: The initrd is not handled in an endian-neutral manner.
@ -61,44 +60,27 @@ struct initrd_context
{
uint8_t* initrd;
size_t initrd_size;
size_t amount_extracted;
initrd_superblock_t* sb;
addr_t initrd_unmap_start;
addr_t initrd_unmap_end;
struct initrd_superblock* sb;
Ref<Descriptor> links;
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");
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 )
if ( !Memory::LookUp(vaddr, NULL, NULL) )
return;
char status[6 + 1];
snprintf(status, sizeof(status), " %3i%% ", percent);
initrd_activity(status, "Extracting ramdisk into initial filesystem");
ctx->last_percent = percent;
addr_t addr = Memory::Unmap(vaddr);
if ( !(ctx->initrd_unmap_start <= addr && addr < ctx->initrd_unmap_end) )
return;
Page::Put(addr, PAGE_USAGE_WASNT_ALLOCATED);
}
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;
}
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 )
return errno = EINVAL, (initrd_inode_t*) NULL;
return errno = EINVAL, (struct initrd_inode*) NULL;
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;
}
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) )
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 )
{
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) )
return dirent->inode;
offset += dirent->reclen;
@ -144,7 +132,9 @@ static uint32_t initrd_directory_open(struct initrd_context* ctx, initrd_inode_t
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) )
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 )
{
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 )
return dirent->name;
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;
}
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) )
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 )
{
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++;
offset += dirent->reclen;
}
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;
uint8_t* data = initrd_inode_get_data(ctx, inode, &filesize);
if ( !data )
return false;
if ( file->truncate(&ctx->ioctx, filesize) != 0 )
return false;
PanicF("initrd: truncate: %m");
size_t sofar = 0;
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;
ssize_t numbytes = file->write(&ctx->ioctx, data + sofar, count);
if ( numbytes <= 0 )
return false;
PanicF("initrd: write: %m");
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);
for ( size_t i = 0; i < numfiles; i++ )
{
const char* name = initrd_directory_get_filename(ctx, inode, i);
if ( !name )
return false;
PanicF("initrd_directory_get_filename: %m");
if ( IsDotOrDotDot(name) )
continue;
uint32_t childino = initrd_directory_open(ctx, inode, name);
if ( !childino )
return false;
initrd_inode_t* child = (initrd_inode_t*) initrd_get_inode(ctx, childino);
PanicF("initrd_directory_open: %s: %m", name);
struct initrd_inode* child =
(struct initrd_inode*) initrd_get_inode(ctx, childino);
mode_t mode = initrd_mode_to_host_mode(child->mode);
if ( INITRD_S_ISDIR(child->mode) )
{
if ( dir->mkdir(&ctx->ioctx, name, mode) && errno != EEXIST )
return false;
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_SEARCH | O_DIRECTORY, 0);
PanicF("initrd: mkdir: %s: %m", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_SEARCH | O_DIRECTORY, 0);
if ( !desc )
return false;
if ( !ExtractNode(ctx, child, desc) )
return false;
PanicF("initrd: %s: %m", name);
ExtractNode(ctx, child, desc);
}
if ( INITRD_S_ISREG(child->mode) )
{
assert(child->nlink != 0);
char link_path[sizeof(childino) * 3];
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 )
{
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 )
return false;
if ( !ExtractNode(ctx, child, desc) )
return false;
PanicF("initrd: %s: %m", name);
ExtractNode(ctx, child, desc);
if ( 2 <= child->nlink )
ctx->links->link(&ctx->ioctx, link_path, desc);
}
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
{
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 size = filesize;
uintptr_t from_aligned = Page::AlignUp(from);
uintptr_t from_distance = from_aligned - from;
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() )
Page::Put(Memory::Unmap(from_aligned + i), PAGE_USAGE_WASNT_ALLOCATED);
UnmapInitrdPage(ctx, from_aligned + i);
Memory::Flush();
}
}
@ -264,122 +262,56 @@ static bool ExtractDir(struct initrd_context* ctx, initrd_inode_t* inode, Ref<De
{
size_t filesize;
uint8_t* data = initrd_inode_get_data(ctx, child, &filesize);
if ( !data )
return false;
char* oldname = new char[filesize + 1];
if ( !oldname )
PanicF("initrd: malloc: %m");
memcpy(oldname, data, filesize);
oldname[filesize] = '\0';
int ret = dir->symlink(&ctx->ioctx, oldname, name);
delete[] oldname;
if ( ret < 0 )
return false;
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_READ | O_SYMLINK_NOFOLLOW, 0);
PanicF("initrd: symlink: %s", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_READ | O_SYMLINK_NOFOLLOW, 0);
if ( 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 )
return false;
PanicF("initrd: chmod: %m");
if ( node->chown(&ctx->ioctx, inode->uid, inode->gid) < 0 )
return false;
PanicF("initrd: chown: %m");
if ( INITRD_S_ISDIR(inode->mode) )
if ( !ExtractDir(ctx, inode, node) )
return false;
ExtractDir(ctx, inode, node);
if ( INITRD_S_ISREG(inode->mode) )
if ( !ExtractFile(ctx, inode, node) )
return false;
ExtractFile(ctx, inode, node);
struct timespec ctime = timespec_make((time_t) inode->ctime, 0);
struct timespec mtime = timespec_make((time_t) inode->mtime, 0);
if ( node->utimens(&ctx->ioctx, &mtime, &ctime, &mtime) < 0 )
return false;
return true;
PanicF("initrd: utimens: %m");
}
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.
addralloc_t initrd_addr_alloc;
if ( !AllocateKernelAddress(&initrd_addr_alloc, size) )
PanicF("Can't allocate 0x%zx bytes of kernel address space for the "
"init ramdisk", size );
if ( ctx->initrd_size < ctx->sb->fssize )
Panic("Initrd header does not match its size");
// Map the physical frames onto our address space.
addr_t mapat = initrd_addr_alloc.from;
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();
if ( desc->mkdir(&ctx->ioctx, ".initrd-links", 0777) != 0 )
PanicF("initrd: .initrd-links: %m");
struct initrd_context ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.initrd = (uint8_t*) mapat;
ctx.initrd_size = size;
ctx.amount_extracted = 0;
ctx.last_percent = -1;
SetupKernelIOCtx(&ctx.ioctx);
if ( !(ctx->links = desc->open(&ctx->ioctx, ".initrd-links",
O_READ | O_DIRECTORY, 0)) )
PanicF("initrd: .initrd-links: %m");
if ( size < sizeof(*ctx.sb) )
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;
ExtractNode(ctx, initrd_get_inode(ctx, ctx->sb->root), desc);
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];
};
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] )
{
if ( ((const char*) dirent.d_name)[0] == '.' )
continue;
ctx.links->unlinkat(&ctx.ioctx, dirent.d_name, AT_REMOVEFILE);
ctx.links->lseek(&ctx.ioctx, 0, SEEK_SET);
ctx->links->unlinkat(&ctx->ioctx, dirent.d_name, AT_REMOVEFILE);
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.
for ( size_t i = 0; i < initrd_addr_alloc.size; i += Page::Size() )
static void ExtractModule(struct multiboot_mod_list* module,
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) )
continue;
addr_t addr = Memory::Unmap(mapat + i);
Page::Put(addr, PAGE_USAGE_WASNT_ALLOCATED);
if ( !Memory::Map(physfrom + i, mapat + i, PROT_KREAD | PROT_KWRITE) )
PanicF("Unable to map the initrd into virtual memory");
}
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.
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

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.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>.
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>
struct multiboot_info;
namespace Sortix {
class Descriptor;
namespace InitRD {
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc);
} // namespace InitRD
void ExtractModules(struct multiboot_info* bootinfo, Ref<Descriptor> root);
} // namespace Sortix

View File

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