#include "init/InitRD.h" #include "bootboot.h" #include "io/Serial.h" #include "memory/KernelMemoryManager.h" #include "std/stdlib.h" #include extern BOOTBOOT bootboot; static inline int get_file_size_in_blocks(InitRD::File f) { return f.size_in_blocks; } inline int InitRD::get_total_blocks() { return bootboot.initrd_size / TAR_BLOCKSIZE; } inline InitRD::TarHeader* InitRD::get_block(int block_index) { return (TarHeader*)(bootboot.initrd_ptr + block_index * TAR_BLOCKSIZE); } inline bool InitRD::is_valid_header(TarHeader* header) { return strncmp(header->magic, TAR_MAGIC, 5) == 0; } 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; } result.addr = KernelMemoryManager::get_unaligned_mappings((void*)(header + TAR_BLOCKSIZE), result.size / 4096 + 1); result.size_in_blocks = result.size / TAR_BLOCKSIZE + 1; return result; } void InitRD::free_file(File& file) { KernelMemoryManager::release_unaligned_mappings(file.addr, file.size / 4096 + 1); } InitRD::File InitRD::open(const char* filename) { int block = 0; int total_blocks = get_total_blocks(); while (block < total_blocks) { TarHeader* hdr = (TarHeader*)KernelMemoryManager::get_unaligned_mapping(get_block(block)); block++; if (hdr->typeflag == 53) { continue; } // Directory if (!is_valid_header(hdr)) { continue; } auto f = get_file(hdr); KernelMemoryManager::release_unaligned_mapping(hdr); if (strncmp(hdr->name, filename, strlen(filename)) == 0) { return f; } block += get_file_size_in_blocks(f); } File nullFile; nullFile.addr = NULL; nullFile.size = 0; memcpy(nullFile.name, "NULL", 5); return nullFile; } void InitRD::close(File& file) { free_file(file); } void InitRD::for_each(void (*callback)(File& f)) { int block = 0; int total_blocks = get_total_blocks(); while (block < total_blocks) { TarHeader* hdr = (TarHeader*)KernelMemoryManager::get_unaligned_mapping(get_block(block)); block++; if (hdr->typeflag == 53) { KernelMemoryManager::release_unaligned_mapping(hdr); continue; } // Directory if (!is_valid_header(hdr)) { KernelMemoryManager::release_unaligned_mapping(hdr); continue; } auto f = get_file(hdr); block += get_file_size_in_blocks(f); KernelMemoryManager::release_unaligned_mapping(hdr); callback(f); close(f); } }