#include "vxBoot/fs/smemfs.h" #include "vxBoot/loader.h" #include "vxBoot/terminal.h" #include #include /* error string list */ const struct ld_error_db image_error_db[] = { {.id = ld_image_success, .strerror = "valid"}, {.id = ld_image_size_error, .strerror = "size error"}, {.id = ld_image_type_error, .strerror = "type error"}, {.id = ld_image_mem_error, .strerror = "out of memory error"}, {.id = ld_image_mem_not_available, .strerror = "memory not available"}, {.id = 0xdeb0cad0, .strerror = NULL}, }; /* hypervisor_elf_loader_image_error(): Display image error information */ int loader_image_error(int const errnum) { return (loader_error(image_error_db, "ELF image ", errnum)); } /* loader_load_image() - Load the program into Virtual Memory */ int loader_image_load(struct kernel * const kernel) { Elf32_Phdr *phdr; uintptr_t paddress; uintptr_t origin; uintptr_t vmin; uintptr_t vmax; /* Walk one time to get the entier program size and check ELF validity. */ vmin = 0xffffffff; vmax = 0x00000000; phdr = kernel->elf.phdr; kernel->memory.program.size = 0; for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i) { if (phdr[i].p_vaddr >= 0xe5007000 && phdr[i].p_vaddr <= 0xe5009000) continue; if (phdr[i].p_vaddr < vmin) vmin = phdr[i].p_vaddr; if (phdr[i].p_vaddr + phdr[i].p_memsz > vmax) vmax = phdr[i].p_vaddr + phdr[i].p_memsz; } kernel->memory.program.size = vmax - vmin; kernel->memory.program.elf.vmin = vmin; kernel->memory.program.elf.vmax = vmax; terminal_log( LOG_DEBUG, "program size = %d\n" "program vmin = %p\n" "program vmax = %p\n", kernel->memory.program.size, kernel->memory.program.elf.vmin, kernel->memory.program.elf.vmax ); /* check available space in RAM to load the image */ if (kernel->memory.program.size >= kernel->hardware.ram.available) return (ld_image_mem_not_available); /* set the kernel's origin address */ origin = kernel->hardware.ram.physical.kernel_addr; origin |= 0xa0000000; kernel->memory.program.start = (void*)origin; /* Now, load all program section into physical memory. To do this, we read each program hdr, generate the "real" physical address of the segment then dump data. Note that the p_filesz can be smaller than p_memsz so, we need to wipe the segment area before the dump. */ for (int i = 0; i < kernel->elf.hdr.e_phnum; ++i){ paddress = (uintptr_t)phdr[i].p_vaddr; if (paddress < 0xe5007000 || paddress > 0xe5009000) { paddress -= vmin; paddress += (uintptr_t)kernel->memory.program.start; } smemfs_pread( kernel->inode, (void*)paddress, phdr[i].p_filesz, phdr[i].p_offset ); memset( (void*)paddress, 0x00, phdr[i].p_memsz - phdr[i].p_filesz ); } /* Generate program entry address */ kernel->entry = (uintptr_t)kernel->elf.hdr.e_entry - vmin; kernel->entry += (uintptr_t)kernel->hardware.ram.physical.kernel_addr; kernel->entry |= (uintptr_t)0x80000000; return (ld_image_success); }