1b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* contrib/arm-neon/linux-auxv.c 2b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 3b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Copyright (c) 2014 Glenn Randers-Pehrson 4b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Written by Mans Rullgard, 2011. 5b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Last changed in libpng 1.6.10 [March 6, 2014] 6b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 7b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * This code is released under the libpng license. 8b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * For conditions of distribution and use, see the disclaimer 9b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * and license in png.h 10b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 11b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * SEE contrib/arm-neon/README before reporting bugs 12b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 13b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * STATUS: COMPILED, TESTED 14b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * BUG REPORTS: png-mng-implement@sourceforge.net 15b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 16b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * png_have_neon implemented for Linux versions which allow access to 17b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * /proc/self/auxv. This is probably faster, cleaner and safer than the code to 18b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece 19b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * of potentially untested code and has more complex dependencies than the code 20b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * to read cpuinfo. 21b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 22b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * This generic __linux__ implementation requires reading /proc/self/auxv and 23b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * looking at each element for one that records NEON capabilities. 24b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 25b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <unistd.h> /* for POSIX 1003.1 */ 26b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <errno.h> /* for EINTR */ 27b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 28b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <sys/types.h> 29b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <sys/stat.h> 30b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <fcntl.h> 31b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <elf.h> 32b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <asm/hwcap.h> 33b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 34b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* A read call may be interrupted, in which case it returns -1 and sets errno to 35b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * EINTR if nothing was done, otherwise (if something was done) a partial read 36b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * may result. 37b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 38b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic size_t 39b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarisafe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes) 40b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{ 41b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari size_t ntotal = 0; 42b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari char *buffer = png_voidcast(char*, buffer_in); 43b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 44b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (nbytes > 0) 45b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 46b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari unsigned int nread; 47b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int iread; 48b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 49b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Passing nread > INT_MAX to read is implementation defined in POSIX 50b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 1003.1, therefore despite the unsigned argument portable code must 51b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * limit the value to INT_MAX! 52b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 53b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (nbytes > INT_MAX) 54b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari nread = INT_MAX; 55b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 56b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 57b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari nread = (unsigned int)/*SAFE*/nbytes; 58b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 59b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari iread = read(fd, buffer, nread); 60b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 61b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (iread == -1) 62b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 63b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* This is the devil in the details, a read can terminate early with 0 64b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * bytes read because of EINTR, yet it still returns -1 otherwise end 65b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * of file cannot be distinguished. 66b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 67b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (errno != EINTR) 68b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 69b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_warning(png_ptr, "/proc read failed"); 70b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return 0; /* I.e., a permanent failure */ 71b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 72b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 73b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 74b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (iread < 0) 75b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 76b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Not a valid 'read' result: */ 77b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_warning(png_ptr, "OS /proc read bug"); 78b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return 0; 79b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 80b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 81b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (iread > 0) 82b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 83b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Continue reading until a permanent failure, or EOF */ 84b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari buffer += iread; 85b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari nbytes -= (unsigned int)/*SAFE*/iread; 86b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ntotal += (unsigned int)/*SAFE*/iread; 87b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 88b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 89b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 90b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return ntotal; 91b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 92b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 93b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return ntotal; /* nbytes == 0 */ 94b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} 95b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 96b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int 97b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraripng_have_neon(png_structp png_ptr) 98b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{ 99b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int fd = open("/proc/self/auxv", O_RDONLY); 100b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari Elf32_auxv_t aux; 101b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 102b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Failsafe: failure to open means no NEON */ 103b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fd == -1) 104b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 105b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_warning(png_ptr, "/proc/self/auxv open failed"); 106b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return 0; 107b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 108b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux) 110b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 111b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0) 112b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 113b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari close(fd); 114b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return 1; 115b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 116b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 117b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 118b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari close(fd); 119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return 0; 120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} 121