2022-09-14 15:55:24 +00:00
|
|
|
#define MODULE "initrd"
|
|
|
|
|
2022-09-05 14:13:51 +00:00
|
|
|
#include "init/InitRD.h"
|
|
|
|
#include "bootboot.h"
|
2022-10-08 19:22:46 +00:00
|
|
|
#include "fs/VFS.h"
|
2022-09-05 14:13:51 +00:00
|
|
|
#include "io/Serial.h"
|
2022-09-14 15:55:24 +00:00
|
|
|
#include "log/Log.h"
|
2022-09-24 19:45:13 +00:00
|
|
|
#include "memory/MemoryManager.h"
|
2022-10-01 10:13:38 +00:00
|
|
|
#include "misc/utils.h"
|
2022-09-05 14:13:51 +00:00
|
|
|
#include "std/stdlib.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
extern BOOTBOOT bootboot;
|
|
|
|
|
2022-09-19 15:06:08 +00:00
|
|
|
static void* initrd_base;
|
2022-09-25 15:41:34 +00:00
|
|
|
static bool initrd_initialized = false;
|
|
|
|
|
2022-10-08 19:22:46 +00:00
|
|
|
static VFS::Node initrd_root;
|
|
|
|
|
2022-09-25 15:41:34 +00:00
|
|
|
bool InitRD::is_initialized()
|
|
|
|
{
|
|
|
|
return initrd_initialized;
|
|
|
|
}
|
2022-09-19 15:06:08 +00:00
|
|
|
|
2022-10-06 15:13:34 +00:00
|
|
|
static inline uint64_t get_file_size_in_blocks(InitRD::File f)
|
2022-09-05 14:13:51 +00:00
|
|
|
{
|
|
|
|
return f.size_in_blocks;
|
|
|
|
}
|
|
|
|
|
2022-10-06 15:13:34 +00:00
|
|
|
inline uint64_t InitRD::get_total_blocks()
|
2022-09-05 14:13:51 +00:00
|
|
|
{
|
|
|
|
return bootboot.initrd_size / TAR_BLOCKSIZE;
|
|
|
|
}
|
|
|
|
|
2022-10-06 15:13:34 +00:00
|
|
|
inline InitRD::TarHeader* InitRD::get_block(uint64_t block_index)
|
2022-09-05 14:13:51 +00:00
|
|
|
{
|
2022-09-19 15:06:08 +00:00
|
|
|
return (TarHeader*)((uintptr_t)initrd_base + block_index * TAR_BLOCKSIZE);
|
2022-09-05 14:13:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool InitRD::is_valid_header(TarHeader* header)
|
|
|
|
{
|
|
|
|
return strncmp(header->magic, TAR_MAGIC, 5) == 0;
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:41:43 +00:00
|
|
|
uint64_t InitRD::get_file_physical_address(InitRD::File& file)
|
|
|
|
{
|
|
|
|
return (uint64_t)file.addr - (uint64_t)initrd_base + (uint64_t)bootboot.initrd_ptr;
|
|
|
|
}
|
|
|
|
|
2022-09-05 14:13:51 +00:00
|
|
|
InitRD::File InitRD::get_file(TarHeader* header)
|
|
|
|
{
|
|
|
|
File result;
|
|
|
|
result.size = 0;
|
|
|
|
memcpy(result.name, header->name, 100);
|
|
|
|
int multiplier =
|
|
|
|
1; // why they decided to store the size as an octal-encoded string instead of an integer is beyond me
|
|
|
|
for (int i = 10; i >= 0; i--)
|
|
|
|
{
|
|
|
|
result.size += (multiplier * (header->size[i] - 48));
|
|
|
|
multiplier *= 8;
|
|
|
|
}
|
2022-09-19 15:06:08 +00:00
|
|
|
result.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE);
|
2022-10-01 10:13:38 +00:00
|
|
|
result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size);
|
2022-09-05 14:13:51 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-09-10 20:15:19 +00:00
|
|
|
InitRD::File InitRD::open(const char* filename)
|
2022-09-05 14:13:51 +00:00
|
|
|
{
|
2022-10-06 15:13:34 +00:00
|
|
|
uint64_t block = 0;
|
|
|
|
uint64_t total_blocks = get_total_blocks();
|
2022-09-05 14:13:51 +00:00
|
|
|
while (block < total_blocks)
|
|
|
|
{
|
2022-09-19 15:06:08 +00:00
|
|
|
TarHeader* hdr = (TarHeader*)get_block(block);
|
2022-09-19 17:04:14 +00:00
|
|
|
if (hdr->typeflag == 53)
|
|
|
|
{
|
|
|
|
block++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!is_valid_header(hdr))
|
2022-09-14 15:55:24 +00:00
|
|
|
{
|
|
|
|
block++;
|
|
|
|
continue;
|
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
auto f = get_file(hdr);
|
|
|
|
if (strncmp(hdr->name, filename, strlen(filename)) == 0) { return f; }
|
2022-09-14 15:55:24 +00:00
|
|
|
block += get_file_size_in_blocks(f) + 1;
|
2022-09-05 14:13:51 +00:00
|
|
|
}
|
|
|
|
File nullFile;
|
2022-10-06 15:13:34 +00:00
|
|
|
nullFile.addr = 0;
|
2022-09-05 14:13:51 +00:00
|
|
|
nullFile.size = 0;
|
|
|
|
memcpy(nullFile.name, "NULL", 5);
|
|
|
|
return nullFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitRD::for_each(void (*callback)(File& f))
|
|
|
|
{
|
2022-10-06 15:13:34 +00:00
|
|
|
uint64_t block = 0;
|
|
|
|
uint64_t total_blocks = get_total_blocks();
|
2022-09-05 14:13:51 +00:00
|
|
|
while (block < total_blocks)
|
|
|
|
{
|
2022-09-19 15:06:08 +00:00
|
|
|
TarHeader* hdr = (TarHeader*)get_block(block);
|
2022-09-19 17:04:14 +00:00
|
|
|
if (hdr->typeflag == 53)
|
|
|
|
{
|
|
|
|
block++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!is_valid_header(hdr))
|
2022-09-11 06:23:32 +00:00
|
|
|
{
|
2022-09-14 15:55:24 +00:00
|
|
|
block++;
|
2022-09-11 06:23:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
auto f = get_file(hdr);
|
2022-09-14 15:55:24 +00:00
|
|
|
block += get_file_size_in_blocks(f) + 1;
|
2022-09-05 14:13:51 +00:00
|
|
|
callback(f);
|
|
|
|
}
|
2022-09-19 15:06:08 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 19:22:46 +00:00
|
|
|
static InitRD::File files[32];
|
|
|
|
static uint32_t total_files = 0;
|
|
|
|
|
|
|
|
static VFS::Node nodes[32];
|
|
|
|
|
|
|
|
int32_t initrd_read(VFS::Node* node, uint32_t offset, uint32_t length, char* buffer)
|
|
|
|
{
|
|
|
|
if (!node) return -1;
|
|
|
|
if (node->inode >= total_files) return -1;
|
|
|
|
InitRD::File& file = files[node->inode];
|
|
|
|
if (offset > file.size) return -1;
|
|
|
|
if (offset + length > file.size) { length = (uint32_t)file.size - offset; }
|
|
|
|
memcpy(buffer, (void*)((uint64_t)file.addr + offset), length);
|
|
|
|
return (int32_t)length;
|
|
|
|
}
|
|
|
|
|
|
|
|
VFS::Node* initrd_scan_root(VFS::Node*, const char* filename)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < total_files; i++)
|
|
|
|
{
|
|
|
|
if (strncmp(nodes[i].name, filename, sizeof(VFS::Node::name)) == 0) { return &nodes[i]; }
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void initrd_scan()
|
|
|
|
{
|
|
|
|
InitRD::for_each([](InitRD::File& f) {
|
|
|
|
if (total_files >= 32) return;
|
|
|
|
kdbgln("registering file %s", f.name);
|
|
|
|
files[total_files++] = f;
|
|
|
|
});
|
|
|
|
for (uint32_t i = 0; i < total_files; i++)
|
|
|
|
{
|
|
|
|
VFS::Node& node = nodes[i];
|
|
|
|
node.inode = i;
|
|
|
|
node.read_func = initrd_read;
|
2022-10-08 19:35:19 +00:00
|
|
|
node.length = files[i].size;
|
2022-10-08 19:22:46 +00:00
|
|
|
strncpy(node.name, files[i].name, sizeof(node.name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-19 15:06:08 +00:00
|
|
|
void InitRD::init()
|
|
|
|
{
|
2022-10-08 12:52:28 +00:00
|
|
|
initrd_base =
|
|
|
|
MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / PAGE_SIZE + 1);
|
2022-10-08 16:16:55 +00:00
|
|
|
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
|
2022-10-08 19:22:46 +00:00
|
|
|
kdbgln("total blocks: %ld", get_total_blocks());
|
|
|
|
initrd_scan();
|
2022-10-08 19:35:19 +00:00
|
|
|
initrd_root.length = 0;
|
2022-10-08 19:22:46 +00:00
|
|
|
initrd_root.inode = (uint64_t)-1;
|
|
|
|
strncpy(initrd_root.name, "initrd", 7);
|
|
|
|
initrd_root.find_func = initrd_scan_root;
|
|
|
|
VFS::mount_root(&initrd_root);
|
2022-10-08 19:35:19 +00:00
|
|
|
VFS::mount_root(0);
|
|
|
|
VFS::mount_root(&initrd_root);
|
2022-10-08 19:22:46 +00:00
|
|
|
kdbgln("mounted initrd at VFS root, total files: %d", total_files);
|
2022-09-25 15:41:34 +00:00
|
|
|
initrd_initialized = true;
|
2022-09-05 14:13:51 +00:00
|
|
|
}
|