mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add support for multiple initrds.
This commit is contained in:
parent
391680a468
commit
475bd7c26e
6 changed files with 160 additions and 327 deletions
|
@ -83,7 +83,6 @@ clock.o \
|
|||
com.o \
|
||||
copy.o \
|
||||
$(CPUDIR)/kthread.o \
|
||||
crc32.o \
|
||||
debugger.o \
|
||||
descriptor.o \
|
||||
disk/ahci/ahci.o \
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue