Skip to content

06 - In-Memory TarFS Ramdisk & ELF64 Binary Loader

BangOS executes userland programs by packaging them into a standard USTAR (Uniform Standard Tape Archive) ramdisk (initrd.tar) loaded into memory at boot time. The kernel parses the archive in RAM and loads 64-bit ELF binaries directly into virtual memory.


📦 USTAR Ramdisk Architecture (kernel/fs/tarfs.c)

The TAR format consists of sequential 512-byte header blocks followed by file data rounded up to 512-byte block boundaries:

+---------------------+-------------------------------+---------------------+-----+
| Header Block #1     | File Payload (Padded to 512B) | Header Block #2     | ... |
| (512 Bytes)         | e.g. /bin/init ELF binary     | (512 Bytes)         |     |
+---------------------+-------------------------------+---------------------+-----+

USTAR Header Structure (struct ustar_header):

struct ustar_header {
    char name[100];     // File path name
    char mode[8];       // File permissions (octal)
    char uid[8];        // User ID (octal)
    char gid[8];        // Group ID (octal)
    char size[12];      // File size in bytes (ASCII octal string)
    char mtime[12];     // Modification time (octal)
    char chksum[8];     // Header checksum
    char typeflag;      // '0' or '\0' for regular file
    char linkname[100]; // Symlink target
    char magic[6];      // "ustar\0"
    char version[2];    // "00"
    char uname[32];     // User name
    char gname[32];     // Group name
    char devmajor[8];
    char devminor[8];
    char prefix[155];
    char pad[12];
} __attribute__((packed));

Octal String Parser & Path Matching:

The size field is encoded as an ASCII octal string (e.g. "00000012345 "):

static uint64_t parse_octal(const char *str, size_t maxlen) {
    uint64_t val = 0;
    for (size_t i = 0; i < maxlen; i++) {
        char c = str[i];
        if (c < '0' || c > '7') break;
        val = (val << 3) | (uint64_t)(c - '0');
    }
    return val;
}

Path matching (tarfs_lookup()) normalizes leading slashes and matches absolute paths (/bin/calc), relative paths (bin/calc), and basename searches (calc).


⚡ ELF64 Binary Loader (kernel/loader/elf.c)

When elf_load_binary() parses an executable image in RAM, it performs validation and memory mapping:

+--------------------------------------------------------------+
| 1. Validate ELF64 Header (Elf64_Ehdr)                        |
|    - Magic: 0x7F 'E' 'L' 'F' (ELF_MAGIC = 0x464C457F)        |
|    - Class: e_ident[4] == 2 (64-Bit Architecture)            |
|    - Target: e_machine == 0x3E (x86_64 Machine)              |
|    - Extract entry point virtual address: ehdr->e_entry      |
+--------------------------------------------------------------+
                               |
                               v
+--------------------------------------------------------------+
| 2. Iterate Program Headers (Elf64_Phdr)                      |
|    - Traverse ehdr->e_phnum headers                          |
|    - Filter for headers where p_type == PT_LOAD              |
+--------------------------------------------------------------+
                               |
                               v
+--------------------------------------------------------------+
| 3. Allocate & Populate PT_LOAD Segments                      |
|    - Calculate page-aligned virtual address: vaddr & ~0xFFF  |
|    - Calculate page count: (memsz + offset + 4095) / 4096    |
|    - alloc_pages(num_pages) allocates physical frames        |
|    - kmemcpy() copies filesz bytes of initialized code/data  |
|    - kmemset() clears (memsz - filesz) bytes to zero (BSS)   |
|    - map_user_pages() registers physical frames into paging  |
+--------------------------------------------------------------+

🔍 Detailed Code Walkthrough

int elf_load_binary(const void *elf_data, size_t elf_size, elf_info_t *out_info) {
    if (!elf_data || elf_size < sizeof(Elf64_Ehdr)) return -1;

    const Elf64_Ehdr *ehdr = (const Elf64_Ehdr *)elf_data;

    // Check ELF Magic & Architecture
    if (*(uint32_t *)ehdr->e_ident != ELF_MAGIC ||
        ehdr->e_ident[4] != 2 || ehdr->e_machine != 0x3E) {
        return -1;
    }

    out_info->entry_point = ehdr->e_entry;
    out_info->num_segments = 0;
    const uint8_t *ph_table = (const uint8_t *)elf_data + ehdr->e_phoff;

    for (uint16_t i = 0; i < ehdr->e_phnum; i++) {
        const Elf64_Phdr *phdr = (const Elf64_Phdr *)(ph_table + i * ehdr->e_phentsize);

        if (phdr->p_type == PT_LOAD) {
            uint64_t vaddr = phdr->p_vaddr;
            uint64_t memsz = phdr->p_memsz;
            uint64_t filesz = phdr->p_filesz;
            uint64_t offset = phdr->p_offset;

            uint64_t page_aligned_vaddr = vaddr & ~0xFFFULL;
            uint64_t vaddr_offset = vaddr & 0xFFFULL;
            size_t num_pages = (memsz + vaddr_offset + PAGE_SIZE - 1) / PAGE_SIZE;

            void *phys_pages = alloc_pages(num_pages);
            if (!phys_pages) return -1;

            // Copy initialized code/data
            if (filesz > 0) {
                kmemcpy((uint8_t *)phys_pages + vaddr_offset,
                        (const uint8_t *)elf_data + offset, filesz);
            }
            // Zero-fill uninitialized BSS section
            if (memsz > filesz) {
                kmemset((uint8_t *)phys_pages + vaddr_offset + filesz,
                        0, memsz - filesz);
            }

            // Map into process page table
            map_user_pages(page_aligned_vaddr, (uint64_t)phys_pages, num_pages);

            // Record segment for fork() and context switching
            out_info->segments[out_info->num_segments].virt_addr = page_aligned_vaddr;
            out_info->segments[out_info->num_segments].phys_addr = (uint64_t)phys_pages;
            out_info->segments[out_info->num_segments].num_pages = num_pages;
            out_info->num_segments++;
        }
    }
    return 0;
}

By cleanly handling PT_LOAD headers, BangOS supports standard static Linux ELF binaries containing separate .text, .rodata, .data, and .bss sections generated by standard toolchains.