summaryrefslogtreecommitdiff
path: root/fs/initramfs.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fs/initramfs.cc')
-rw-r--r--fs/initramfs.cc285
1 files changed, 0 insertions, 285 deletions
diff --git a/fs/initramfs.cc b/fs/initramfs.cc
deleted file mode 100644
index ba10a3e..0000000
--- a/fs/initramfs.cc
+++ /dev/null
@@ -1,285 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * initramfs.cc — Unpack embedded CPIO archive into ramfs
- *
- * The build system embeds a newc-format CPIO archive into the kernel
- * ELF as the section .init.ramfs. The linker script exports
- * __initramfs_start / __initramfs_end symbols.
- *
- * At boot, populate_rootfs() walks the CPIO entries and creates
- * directories and files in the already-mounted ramfs root.
- *
- * Reference: Linux init/initramfs.c
- *
- * CPIO "newc" header format (110 bytes, ASCII hex fields):
- * magic[6] "070701"
- * ino[8] mode[8] uid[8] gid[8] nlink[8] mtime[8]
- * filesize[8] devmajor[8] devminor[8] rdevmajor[8] rdevminor[8]
- * namesize[8] check[8]
- * filename (namesize bytes, NUL terminated, padded to 4-byte boundary)
- * file data (filesize bytes, padded to 4-byte boundary)
- */
-
-#include <lume/klog.h>
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* Linker-provided symbols for the embedded CPIO archive */
-extern "C" const char __initramfs_start[];
-extern "C" const char __initramfs_end[];
-
-/* ramfs inode creation (from fs/ramfs/inode.cc) */
-extern inode* ramfs_get_inode(super_block* sb, const inode* dir,
- uint32 mode, uint32 rdev);
-
-/* Global root dentry (from fs/vfs_init.cc) */
-extern dentry* g_root_dentry;
-
-/* ================================================================== */
-/* CPIO newc header parsing */
-/* ================================================================== */
-
-struct cpio_header {
- char magic[6];
- char ino[8];
- char mode[8];
- char uid[8];
- char gid[8];
- char nlink[8];
- char mtime[8];
- char filesize[8];
- char devmajor[8];
- char devminor[8];
- char rdevmajor[8];
- char rdevminor[8];
- char namesize[8];
- char check[8];
-};
-
-static constexpr int kCpioHeaderSize = 110;
-
-static uint32 parse_hex8(const char* s)
-{
- uint32 val = 0;
- for (int i = 0; i < 8; i++) {
- char c = s[i];
- uint32 nibble;
- if (c >= '0' && c <= '9') nibble = c - '0';
- else if (c >= 'a' && c <= 'f') nibble = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F') nibble = c - 'A' + 10;
- else return val;
- val = (val << 4) | nibble;
- }
- return val;
-}
-
-static inline uint32 align4(uint32 v)
-{
- return (v + 3) & ~3U;
-}
-
-/* ================================================================== */
-/* Path resolution helpers */
-/* ================================================================== */
-
-static dentry* cpio_mkdir_p(dentry* root, const char* path,
- const char** out_name)
-{
- dentry* cur = root;
-
- while (*path == '/') path++;
-
- while (true) {
- const char* slash = path;
- while (*slash && *slash != '/') slash++;
-
- if (*slash == '\0') {
- *out_name = path;
- return cur;
- }
-
- uint32 len = static_cast<uint32>(slash - path);
-
- qstr name;
- name.name = path;
- name.len = len;
- name.hash = full_name_hash(path, len);
-
- dentry* child = d_lookup(cur, &name);
- if (!child) {
- child = d_alloc(cur, &name);
- if (!child) return nullptr;
-
- inode* ip = ramfs_get_inode(cur->d_inode->i_sb, cur->d_inode,
- S_IFDIR | 0755, 0);
- if (!ip) return nullptr;
-
- d_instantiate(child, ip);
- dget(child);
- inc_nlink(cur->d_inode);
- }
-
- cur = child;
- path = slash + 1;
- while (*path == '/') path++;
- }
-}
-
-/* ================================================================== */
-/* populate_rootfs — the main entry point */
-/* ================================================================== */
-
-void populate_rootfs()
-{
- const char* p = __initramfs_start;
- const char* end = __initramfs_end;
- uint64 archive_size = static_cast<uint64>(end - p);
-
- if (archive_size == 0) {
- printk("[initramfs] no embedded archive found\n");
- return;
- }
-
- printk("[initramfs] unpacking %llu bytes...\n", archive_size);
-
- int file_count = 0;
- int dir_count = 0;
-
- while (p + kCpioHeaderSize <= end) {
- auto* hdr = reinterpret_cast<const cpio_header*>(p);
-
- /* Verify magic */
- if (hdr->magic[0] != '0' || hdr->magic[1] != '7' ||
- hdr->magic[2] != '0' || hdr->magic[3] != '7' ||
- hdr->magic[4] != '0' || hdr->magic[5] != '1') {
- printk("[initramfs] bad cpio magic at offset %llu\n",
- static_cast<uint64>(p - __initramfs_start));
- break;
- }
-
- uint32 mode = parse_hex8(hdr->mode);
- uint32 filesize = parse_hex8(hdr->filesize);
- uint32 namesize = parse_hex8(hdr->namesize);
-
- const char* name = p + kCpioHeaderSize;
- uint32 name_padded = align4(kCpioHeaderSize + namesize);
- const char* data = p + name_padded;
- uint32 data_padded = align4(filesize);
-
- const char* next = p + name_padded + data_padded;
-
- /* Check for TRAILER!!! end-of-archive marker */
- if (namesize == 11 && name[0] == 'T' && name[1] == 'R' &&
- name[2] == 'A' && name[3] == 'I' && name[4] == 'L' &&
- name[5] == 'E' && name[6] == 'R' && name[7] == '!' &&
- name[8] == '!' && name[9] == '!') {
- break;
- }
-
- /* Skip "." entry */
- if (namesize == 2 && name[0] == '.' && name[1] == '\0') {
- p = next;
- continue;
- }
-
- /* Resolve parent directory, creating intermediate dirs */
- const char* basename = nullptr;
- dentry* parent = cpio_mkdir_p(g_root_dentry, name, &basename);
- if (!parent || !basename || basename[0] == '\0') {
- p = next;
- continue;
- }
-
- /* Build qstr for the final component */
- uint32 blen = 0;
- while (basename[blen] && basename[blen] != '/') blen++;
-
- qstr bname;
- bname.name = basename;
- bname.len = blen;
- bname.hash = full_name_hash(basename, blen);
-
- if (S_ISDIR(mode)) {
- dentry* existing = d_lookup(parent, &bname);
- if (!existing) {
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFDIR | (mode & 0777), 0);
- if (ip) {
- d_instantiate(de, ip);
- dget(de);
- inc_nlink(parent->d_inode);
- dir_count++;
- }
- }
- }
- } else if (S_ISREG(mode)) {
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFREG | (mode & 0777), 0);
- if (ip) {
- d_instantiate(de, ip);
- dget(de);
-
- /* Write file content via ramfs write path */
- if (filesize > 0 && ip->i_fop && ip->i_fop->write) {
- file tmp_fp = {};
- tmp_fp.f_inode = ip;
- tmp_fp.f_path.de = de;
- tmp_fp.f_pos = 0;
- tmp_fp.f_flags = O_WRONLY;
- tmp_fp.f_count.store(1);
-
- int64 pos = 0;
- ip->i_fop->write(&tmp_fp, data,
- filesize, &pos);
- }
-
- file_count++;
- printk("[initramfs] %s (%u bytes, mode %03o)\n",
- name, filesize, mode & 0777);
- }
- }
- } else if (S_ISLNK(mode)) {
- /* Symlink: file data is the target path (not NUL-terminated).
- * Linux: init/initramfs.c do_symlink() */
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFLNK | 0777, 0);
- if (ip) {
- /* Store symlink target in inode.
- * Allocate a kernel buffer and copy the target. */
- char* target = new char[filesize + 1];
- if (target) {
- for (uint32 i = 0; i < filesize; i++)
- target[i] = data[i];
- target[filesize] = '\0';
- ip->i_link = target;
- }
-
- d_instantiate(de, ip);
- dget(de);
- file_count++;
- printk("[initramfs] %s -> %s (symlink)\n",
- name, target ? target : "?");
- }
- }
- }
-
- p = next;
- }
-
- printk("[initramfs] done: %d files, %d dirs\n",
- file_count, dir_count);
-}