fukasawa e60969
/* contrib/arm-neon/linux-auxv.c
fukasawa e60969
 *
fukasawa e60969
 * Copyright (c) 2014 Glenn Randers-Pehrson
fukasawa e60969
 * Written by Mans Rullgard, 2011.
fukasawa e60969
 * Last changed in libpng 1.6.10 [March 6, 2014]
fukasawa e60969
 *
fukasawa e60969
 * This code is released under the libpng license.
fukasawa e60969
 * For conditions of distribution and use, see the disclaimer
fukasawa e60969
 * and license in png.h
fukasawa e60969
 *
fukasawa e60969
 * SEE contrib/arm-neon/README before reporting bugs
fukasawa e60969
 *
fukasawa e60969
 * STATUS: COMPILED, TESTED
fukasawa e60969
 * BUG REPORTS: png-mng-implement@sourceforge.net
fukasawa e60969
 *
fukasawa e60969
 * png_have_neon implemented for Linux versions which allow access to
fukasawa e60969
 * /proc/self/auxv.  This is probably faster, cleaner and safer than the code to
fukasawa e60969
 * read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece
fukasawa e60969
 * of potentially untested code and has more complex dependencies than the code
fukasawa e60969
 * to read cpuinfo.
fukasawa e60969
 *
fukasawa e60969
 * This generic __linux__ implementation requires reading /proc/self/auxv and
fukasawa e60969
 * looking at each element for one that records NEON capabilities.
fukasawa e60969
 */
fukasawa e60969
#include <unistd.h> /* for POSIX 1003.1 */</unistd.h>
fukasawa e60969
#include <errno.h>  /* for EINTR */</errno.h>
fukasawa e60969
fukasawa e60969
#include <sys types.h=""></sys>
fukasawa e60969
#include <sys stat.h=""></sys>
fukasawa e60969
#include <fcntl.h></fcntl.h>
fukasawa e60969
#include <elf.h></elf.h>
fukasawa e60969
#include <asm hwcap.h=""></asm>
fukasawa e60969
fukasawa e60969
/* A read call may be interrupted, in which case it returns -1 and sets errno to
fukasawa e60969
 * EINTR if nothing was done, otherwise (if something was done) a partial read
fukasawa e60969
 * may result.
fukasawa e60969
 */
fukasawa e60969
static size_t
fukasawa e60969
safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
fukasawa e60969
{
fukasawa e60969
   size_t ntotal = 0;
fukasawa e60969
   char *buffer = png_voidcast(char*, buffer_in);
fukasawa e60969
fukasawa e60969
   while (nbytes > 0)
fukasawa e60969
   {
fukasawa e60969
      unsigned int nread;
fukasawa e60969
      int iread;
fukasawa e60969
fukasawa e60969
      /* Passing nread > INT_MAX to read is implementation defined in POSIX
fukasawa e60969
       * 1003.1, therefore despite the unsigned argument portable code must
fukasawa e60969
       * limit the value to INT_MAX!
fukasawa e60969
       */
fukasawa e60969
      if (nbytes > INT_MAX)
fukasawa e60969
         nread = INT_MAX;
fukasawa e60969
fukasawa e60969
      else
fukasawa e60969
         nread = (unsigned int)/*SAFE*/nbytes;
fukasawa e60969
fukasawa e60969
      iread = read(fd, buffer, nread);
fukasawa e60969
fukasawa e60969
      if (iread == -1)
fukasawa e60969
      {
fukasawa e60969
         /* This is the devil in the details, a read can terminate early with 0
fukasawa e60969
          * bytes read because of EINTR, yet it still returns -1 otherwise end
fukasawa e60969
          * of file cannot be distinguished.
fukasawa e60969
          */
fukasawa e60969
         if (errno != EINTR)
fukasawa e60969
         {
fukasawa e60969
            png_warning(png_ptr, "/proc read failed");
fukasawa e60969
            return 0; /* I.e., a permanent failure */
fukasawa e60969
         }
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      else if (iread < 0)
fukasawa e60969
      {
fukasawa e60969
         /* Not a valid 'read' result: */
fukasawa e60969
         png_warning(png_ptr, "OS /proc read bug");
fukasawa e60969
         return 0;
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      else if (iread > 0)
fukasawa e60969
      {
fukasawa e60969
         /* Continue reading until a permanent failure, or EOF */
fukasawa e60969
         buffer += iread;
fukasawa e60969
         nbytes -= (unsigned int)/*SAFE*/iread;
fukasawa e60969
         ntotal += (unsigned int)/*SAFE*/iread;
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      else
fukasawa e60969
         return ntotal;
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
   return ntotal; /* nbytes == 0 */
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
static int
fukasawa e60969
png_have_neon(png_structp png_ptr)
fukasawa e60969
{
fukasawa e60969
   int fd = open("/proc/self/auxv", O_RDONLY);
fukasawa e60969
   Elf32_auxv_t aux;
fukasawa e60969
fukasawa e60969
   /* Failsafe: failure to open means no NEON */
fukasawa e60969
   if (fd == -1)
fukasawa e60969
   {
fukasawa e60969
      png_warning(png_ptr, "/proc/self/auxv open failed");
fukasawa e60969
      return 0;
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
   while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
fukasawa e60969
   {
fukasawa e60969
      if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
fukasawa e60969
      {
fukasawa e60969
         close(fd);
fukasawa e60969
         return 1;
fukasawa e60969
      }
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
   close(fd);
fukasawa e60969
   return 0;
fukasawa e60969
}