/*static*/ status_t ELFLoader<Class>::Create(int fd, preloaded_image** _image) { ImageType* image = (ImageType*)kernel_args_malloc(sizeof(ImageType)); if (image == NULL) return B_NO_MEMORY; ssize_t length = read_pos(fd, 0, &image->elf_header, sizeof(EhdrType)); if (length < (ssize_t)sizeof(EhdrType)) { kernel_args_free(image); return B_BAD_TYPE; } const EhdrType& elfHeader = image->elf_header; if (memcmp(elfHeader.e_ident, ELF_MAGIC, 4) != 0 || elfHeader.e_ident[4] != Class::kIdentClass || elfHeader.e_phoff == 0 || !elfHeader.IsHostEndian() || elfHeader.e_phentsize != sizeof(PhdrType)) { kernel_args_free(image); return B_BAD_TYPE; } image->elf_class = elfHeader.e_ident[EI_CLASS]; *_image = image; return B_OK; }
status_t add_safe_mode_settings(char* settings) { if (settings == NULL || settings[0] == '\0') return B_OK; size_t length = strlen(settings); char* buffer = (char*)kernel_args_malloc(length + 1); if (buffer == NULL) return B_NO_MEMORY; driver_settings_file* file = (driver_settings_file*)kernel_args_malloc( sizeof(driver_settings_file)); if (file == NULL) { kernel_args_free(buffer); return B_NO_MEMORY; } strlcpy(file->name, B_SAFEMODE_DRIVER_SETTINGS, sizeof(file->name)); memcpy(buffer, settings, length + 1); file->buffer = buffer; file->size = length; // add it to the list file->next = gKernelArgs.driver_settings; gKernelArgs.driver_settings = file; return B_OK; }
status_t elf_load_image(Directory *directory, const char *path) { preloaded_image *image; TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path)); int fd = open_from(directory, path, O_RDONLY); if (fd < 0) return fd; // check if this file has already been loaded struct stat stat; if (fstat(fd, &stat) < 0) return errno; image = gKernelArgs.preloaded_images; for (; image != NULL; image = image->next) { if (image->inode == stat.st_ino) { // file has already been loaded, no need to load it twice! close(fd); return B_OK; } } // we still need to load it, so do it image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image)); if (image == NULL) { close(fd); return B_NO_MEMORY; } status_t status = elf_load_image(fd, image); if (status == B_OK) { image->name = kernel_args_strdup(path); image->inode = stat.st_ino; // insert to kernel args image->next = gKernelArgs.preloaded_images; gKernelArgs.preloaded_images = image; } else kernel_args_free(image); close(fd); return status; }
static status_t load_driver_settings_file(Directory* directory, const char* name) { int fd = open_from(directory, name, O_RDONLY); if (fd < 0) return fd; struct stat stat; if (fstat(fd, &stat) < 0) return errno; char* buffer = (char*)kernel_args_malloc(stat.st_size + 1); if (buffer == NULL) return B_NO_MEMORY; if (read(fd, buffer, stat.st_size) != stat.st_size) return B_IO_ERROR; driver_settings_file* file = (driver_settings_file*)kernel_args_malloc( sizeof(driver_settings_file)); if (file == NULL) { kernel_args_free(buffer); return B_NO_MEMORY; } buffer[stat.st_size] = '\0'; // null terminate the buffer strlcpy(file->name, name, sizeof(file->name)); file->buffer = buffer; file->size = stat.st_size; // add it to the list file->next = gKernelArgs.driver_settings; gKernelArgs.driver_settings = file; return B_OK; }
/*static*/ status_t ELFLoader<Class>::_LoadSymbolTable(int fd, ImageType* image) { const EhdrType& elfHeader = image->elf_header; SymType* symbolTable = NULL; ShdrType* stringHeader = NULL; uint32 numSymbols = 0; char* stringTable; status_t status; // get section headers ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize; ShdrType* sectionHeaders = (ShdrType*)malloc(size); if (sectionHeaders == NULL) { dprintf("error allocating space for section headers\n"); return B_NO_MEMORY; } ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size); if (length < size) { TRACE(("error reading in program headers\n")); status = B_ERROR; goto error1; } // find symbol table in section headers for (int32 i = 0; i < elfHeader.e_shnum; i++) { if (sectionHeaders[i].sh_type == SHT_SYMTAB) { stringHeader = §ionHeaders[sectionHeaders[i].sh_link]; if (stringHeader->sh_type != SHT_STRTAB) { TRACE(("doesn't link to string table\n")); status = B_BAD_DATA; goto error1; } // read in symbol table size = sectionHeaders[i].sh_size; symbolTable = (SymType*)kernel_args_malloc(size); if (symbolTable == NULL) { status = B_NO_MEMORY; goto error1; } length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable, size); if (length < size) { TRACE(("error reading in symbol table\n")); status = B_ERROR; goto error1; } numSymbols = size / sizeof(SymType); break; } } if (symbolTable == NULL) { TRACE(("no symbol table\n")); status = B_BAD_VALUE; goto error1; } // read in string table size = stringHeader->sh_size; stringTable = (char*)kernel_args_malloc(size); if (stringTable == NULL) { status = B_NO_MEMORY; goto error2; } length = read_pos(fd, stringHeader->sh_offset, stringTable, size); if (length < size) { TRACE(("error reading in string table\n")); status = B_ERROR; goto error3; } TRACE(("loaded %ld debug symbols\n", numSymbols)); // insert tables into image image->debug_symbols = symbolTable; image->num_debug_symbols = numSymbols; image->debug_string_table = stringTable; image->debug_string_table_size = size; free(sectionHeaders); return B_OK; error3: kernel_args_free(stringTable); error2: kernel_args_free(symbolTable); error1: free(sectionHeaders); return status; }
/*static*/ status_t ELFLoader<Class>::Load(int fd, preloaded_image* _image) { size_t totalSize; ssize_t length; status_t status; void* mappedRegion = NULL; ImageType* image = static_cast<ImageType*>(_image); const EhdrType& elfHeader = image->elf_header; ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize; PhdrType* programHeaders = (PhdrType*)malloc(size); if (programHeaders == NULL) { dprintf("error allocating space for program headers\n"); status = B_NO_MEMORY; goto error1; } length = read_pos(fd, elfHeader.e_phoff, programHeaders, size); if (length < size) { TRACE(("error reading in program headers\n")); status = B_ERROR; goto error1; } // create an area large enough to hold the image image->data_region.size = 0; image->text_region.size = 0; for (int32 i = 0; i < elfHeader.e_phnum; i++) { PhdrType& header = programHeaders[i]; switch (header.p_type) { case PT_LOAD: break; case PT_DYNAMIC: image->dynamic_section.start = header.p_vaddr; image->dynamic_section.size = header.p_memsz; continue; case PT_INTERP: case PT_PHDR: case PT_ARM_UNWIND: // known but unused type continue; default: dprintf("unhandled pheader type 0x%" B_PRIx32 "\n", header.p_type); continue; } RegionType* region; if (header.IsReadWrite()) { if (image->data_region.size != 0) { dprintf("elf: rw already handled!\n"); continue; } region = &image->data_region; } else if (header.IsExecutable()) { if (image->text_region.size != 0) { dprintf("elf: ro already handled!\n"); continue; } region = &image->text_region; } else continue; region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE); region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); region->delta = -region->start; TRACE(("segment %ld: start = 0x%llx, size = %llu, delta = %llx\n", i, (uint64)region->start, (uint64)region->size, (int64)(AddrType)region->delta)); } // found both, text and data? if (image->data_region.size == 0 || image->text_region.size == 0) { dprintf("Couldn't find both text and data segment!\n"); status = B_BAD_DATA; goto error1; } // get the segment order RegionType* firstRegion; RegionType* secondRegion; if (image->text_region.start < image->data_region.start) { firstRegion = &image->text_region; secondRegion = &image->data_region; } else { firstRegion = &image->data_region; secondRegion = &image->text_region; } // The kernel and the modules are relocatable, thus AllocateRegion() // can automatically allocate an address, but shall prefer the specified // base address. totalSize = secondRegion->start + secondRegion->size - firstRegion->start; if (Class::AllocateRegion(&firstRegion->start, totalSize, B_READ_AREA | B_WRITE_AREA, &mappedRegion) != B_OK) { status = B_NO_MEMORY; goto error1; } // initialize the region pointers to the allocated region secondRegion->start += firstRegion->start + firstRegion->delta; image->data_region.delta += image->data_region.start; image->text_region.delta += image->text_region.start; TRACE(("text: start 0x%llx, size 0x%llx, delta 0x%llx\n", (uint64)image->text_region.start, (uint64)image->text_region.size, (int64)(AddrType)image->text_region.delta)); TRACE(("data: start 0x%llx, size 0x%llx, delta 0x%llx\n", (uint64)image->data_region.start, (uint64)image->data_region.size, (int64)(AddrType)image->data_region.delta)); // load program data for (int32 i = 0; i < elfHeader.e_phnum; i++) { PhdrType& header = programHeaders[i]; if (header.p_type != PT_LOAD) continue; RegionType* region; if (header.IsReadWrite()) region = &image->data_region; else if (header.IsExecutable()) region = &image->text_region; else continue; TRACE(("load segment %ld (%llu bytes) mapped at %p...\n", i, (uint64)header.p_filesz, Class::Map(region->start))); length = read_pos(fd, header.p_offset, Class::Map(region->start + (header.p_vaddr % B_PAGE_SIZE)), header.p_filesz); if (length < (ssize_t)header.p_filesz) { status = B_BAD_DATA; dprintf("error reading in seg %" B_PRId32 "\n", i); goto error2; } // Clear anything above the file size (that may also contain the BSS // area) uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; if (offset < region->size) memset(Class::Map(region->start + offset), 0, region->size - offset); } // offset dynamic section, and program entry addresses by the delta of the // regions image->dynamic_section.start += image->text_region.delta; image->elf_header.e_entry += image->text_region.delta; image->num_debug_symbols = 0; image->debug_symbols = NULL; image->debug_string_table = NULL; if (sLoadElfSymbols) _LoadSymbolTable(fd, image); free(programHeaders); return B_OK; error2: if (mappedRegion != NULL) platform_free_region(mappedRegion, totalSize); error1: free(programHeaders); kernel_args_free(image); return status; }
extern "C" status_t video_display_splash(addr_t frameBuffer) { if (!gKernelArgs.frame_buffer.enabled) return B_NO_INIT; // clear the video memory memset((void*)frameBuffer, 0, gKernelArgs.frame_buffer.physical_buffer.size); uint8* uncompressedLogo = NULL; unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight; switch (gKernelArgs.frame_buffer.depth) { case 8: platform_set_palette(k8BitPalette); uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize); if (uncompressedLogo == NULL) return B_NO_MEMORY; uncompress(kSplashLogo8BitCompressedImage, sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo, uncompressedSize); break; default: // 24 bits is assumed here uncompressedSize *= 3; uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize); if (uncompressedLogo == NULL) return B_NO_MEMORY; uncompress(kSplashLogo24BitCompressedImage, sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo, uncompressedSize); break; } // TODO: support 4-bit indexed version of the images! // render splash logo uint16 iconsHalfHeight = kSplashIconsHeight / 2; int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width); int height = min_c(kSplashLogoHeight + iconsHalfHeight, gKernelArgs.frame_buffer.height); int placementX = max_c(0, min_c(100, kSplashLogoPlacementX)); int placementY = max_c(0, min_c(100, kSplashLogoPlacementY)); int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100; height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height); switch (gKernelArgs.frame_buffer.depth) { case 8: break; } video_blit_image(frameBuffer, uncompressedLogo, width, height, kSplashLogoWidth, x, y); kernel_args_free(uncompressedLogo); const uint8* lowerHalfIconImage; uncompressedSize = kSplashIconsWidth * kSplashIconsHeight; switch (gKernelArgs.frame_buffer.depth) { case 8: // pointer into the lower half of the icons image data gKernelArgs.boot_splash = (uint8*)kernel_args_malloc(uncompressedSize); if (gKernelArgs.boot_splash == NULL) return B_NO_MEMORY; uncompress(kSplashIcons8BitCompressedImage, sizeof(kSplashIcons8BitCompressedImage), gKernelArgs.boot_splash, uncompressedSize); lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash + (kSplashIconsWidth * iconsHalfHeight); break; default: // 24bits is assumed here uncompressedSize *= 3; // pointer into the lower half of the icons image data gKernelArgs.boot_splash = (uint8*)kernel_args_malloc(uncompressedSize); if (gKernelArgs.boot_splash == NULL) return B_NO_MEMORY; uncompress(kSplashIcons24BitCompressedImage, sizeof(kSplashIcons24BitCompressedImage), gKernelArgs.boot_splash, uncompressedSize); lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash + (kSplashIconsWidth * iconsHalfHeight) * 3; break; } // render initial (grayed out) icons // the grayed out version is the lower half of the icons image width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width); height = min_c(kSplashLogoHeight + iconsHalfHeight, gKernelArgs.frame_buffer.height); placementX = max_c(0, min_c(100, kSplashIconsPlacementX)); placementY = max_c(0, min_c(100, kSplashIconsPlacementY)); x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height) * placementY / 100; height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height); video_blit_image(frameBuffer, lowerHalfIconImage, width, height, kSplashIconsWidth, x, y); return B_OK; }