/** * @file initrd.c * Filesystem module for handling the initrd * * Copyright (C) 2018 Clyne Sullivan * * This program 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. * * This program 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 this program. If not, see . */ #include #include #include typedef struct { char *address; uint32_t size; } initrd_info; extern uint8_t _binary_initrd_img_start[]; extern uint8_t _binary_initrd_img_size[]; static const uint8_t *initrd_start = (uint8_t *)_binary_initrd_img_start; static const uint32_t initrd_size = (uint32_t)_binary_initrd_img_size; void *initrd_open(const char *file); uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer); int initrd_close(vfs_file_info *info); int initrd_seek(vfs_file_info *info, uint32_t offset, int whence); char *initrd_getfile(uint32_t offset); static const vfs_volume_funcs initrd_funcs = { initrd_open, initrd_close, initrd_read, 0, // write 0, // readdir initrd_seek }; int initrd_strncmp(const char *a, const char *b, unsigned int n) { for (unsigned int i = 0; i < n; i++) { if (a[i] != b[i]) return 1; } return 0; } void initrd_init(void) { vfs_mount(&initrd_funcs, VFS_READONLY); } void *initrd_open(const char *file) { char *ptr; for (uint32_t i = 0; ptr = initrd_getfile(i), ptr != 0; i++) { uint32_t len = *((uint32_t *)ptr); if (!initrd_strncmp(file, ptr + 4, len)) { initrd_info *file = (initrd_info *)malloc( sizeof(initrd_info)); file->address = ptr + len + 8; file->size = *(uint32_t *)(ptr + len + 4); return file; } } return 0; } int initrd_close(vfs_file_info *info) { // Nothing to do free(info->fsinfo); return 0; } uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer) { initrd_info *iinfo = (initrd_info *)info->fsinfo; if (iinfo == 0 || iinfo->address == 0) return 0; uint32_t i; for (i = 0; i < count; i++) { if (info->pos >= iinfo->size) break; buffer[info->pos] = iinfo->address[info->pos]; info->pos++; } return i; } int initrd_seek(vfs_file_info *info, uint32_t offset, int whence) { initrd_info *iinfo = (initrd_info *)info->fsinfo; if (iinfo == 0 || iinfo->address == 0) return 0; if (whence == SEEK_SET) info->pos = offset; else if (whence == SEEK_CUR) info->pos += offset; else if (whence == SEEK_END) info->pos = iinfo->size + offset; else return -1; return 0; } char *initrd_getfile(uint32_t offset) { char *ptr = (char *)initrd_start; for (uint32_t i = 0; i < offset; i++) { uint32_t len = *((uint32_t *)ptr); uint32_t datalen = *((uint32_t *)(ptr + 4 + len)); ptr += len + datalen + 8; if (ptr >= (char *)(initrd_start + initrd_size)) return 0; } return ptr; }