(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
ia64/
ioperm.c
       1  /* Copyright (C) 1999-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  /* I/O access is restricted to ISA port space (ports 0..65535).
      19     Modern devices hopefully are sane enough not to put any performance
      20     critical registers in i/o space.
      21  
      22     On the first call to ioperm() or iopl(), the entire (E)ISA port
      23     space is mapped into the virtual address space at address io.base.
      24     mprotect() calls are then used to enable/disable access to ports.
      25     Per 4KB page, there are 4 I/O ports.  */
      26  
      27  #include <errno.h>
      28  #include <fcntl.h>
      29  #include <ctype.h>
      30  #include <stdlib.h>
      31  #include <string.h>
      32  #include <unistd.h>
      33  
      34  #include <sys/types.h>
      35  #include <sys/mman.h>
      36  
      37  #define MAX_PORT	0x10000
      38  
      39  /*
      40   * Memory fence w/accept.  This should never be used in code that is
      41   * not IA-64 specific.
      42   */
      43  #define __ia64_mf_a()	__asm__ __volatile__ ("mf.a" ::: "memory")
      44  
      45  static struct
      46    {
      47      unsigned long int base;
      48      unsigned long int page_mask;
      49    }
      50  io;
      51  
      52  __inline__ unsigned long int
      53  io_offset (unsigned long int port)
      54  {
      55  	return ((port >> 2) << 12) | (port & 0xfff);
      56  }
      57  
      58  int
      59  _ioperm (unsigned long int from, unsigned long int num, int turn_on)
      60  {
      61    unsigned long int base;
      62  
      63    /* this test isn't as silly as it may look like; consider overflows! */
      64    if (from >= MAX_PORT || from + num > MAX_PORT)
      65      {
      66        __set_errno (EINVAL);
      67        return -1;
      68      }
      69  
      70    if (turn_on)
      71      {
      72        if (!io.base)
      73  	{
      74  	  unsigned long phys_io_base, len;
      75  	  int fd;
      76  
      77  	  io.page_mask = ~(__getpagesize() - 1);
      78  
      79  	  /* get I/O base physical address from ar.k0 as per PRM: */
      80  	  __asm__ ("mov %0=ar.k0" : "=r"(phys_io_base));
      81  
      82  	  /* The O_SYNC flag tells the /dev/mem driver to map the
      83               memory uncached: */
      84  	  fd = __open ("/dev/mem", O_RDWR | O_SYNC);
      85  	  if (fd < 0)
      86  	    return -1;
      87  
      88  	  len = io_offset (MAX_PORT);
      89  	  /* see comment below */
      90  	  base = (unsigned long int) __mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
      91  						fd, phys_io_base);
      92  	  __close (fd);
      93  
      94  	  if ((long) base == -1)
      95  	    return -1;
      96  
      97  	  io.base = base;
      98  	}
      99      }
     100    else
     101      {
     102        if (!io.base)
     103  	return 0;	/* never was turned on... */
     104      }
     105  
     106    /* We can't do mprotect because that would cause us to lose the
     107       uncached flag that the /dev/mem driver turned on.  A MAP_UNCACHED
     108       flag seems so much cleaner...
     109  
     110       See the history of this file for a version that tried mprotect.  */
     111    return 0;
     112  }
     113  
     114  int
     115  _iopl (unsigned int level)
     116  {
     117    if (level > 3)
     118      {
     119        __set_errno (EINVAL);
     120        return -1;
     121      }
     122    if (level)
     123      {
     124        int retval = _ioperm (0, MAX_PORT, 1);
     125        /* Match the documented error returns of the x86 version.  */
     126        if (retval < 0 && errno == EACCES)
     127  	__set_errno (EPERM);
     128        return retval;
     129      }
     130    return 0;
     131  }
     132  
     133  unsigned int
     134  _inb (unsigned long int port)
     135  {
     136    volatile unsigned char *addr = (void *) io.base + io_offset (port);
     137    unsigned char ret;
     138  
     139    ret = *addr;
     140    __ia64_mf_a();
     141    return ret;
     142  }
     143  
     144  unsigned int
     145  _inw (unsigned long int port)
     146  {
     147    volatile unsigned short *addr = (void *) io.base + io_offset (port);
     148    unsigned short ret;
     149  
     150    ret = *addr;
     151    __ia64_mf_a();
     152    return ret;
     153  }
     154  
     155  unsigned int
     156  _inl (unsigned long int port)
     157  {
     158    volatile unsigned int *addr = (void *) io.base + io_offset (port);
     159    unsigned int ret;
     160  
     161    ret = *addr;
     162    __ia64_mf_a();
     163    return ret;
     164  }
     165  
     166  void
     167  _outb (unsigned char val, unsigned long int port)
     168  {
     169    volatile unsigned char *addr = (void *) io.base + io_offset (port);
     170  
     171    *addr = val;
     172    __ia64_mf_a();
     173  }
     174  
     175  void
     176  _outw (unsigned short val, unsigned long int port)
     177  {
     178    volatile unsigned short *addr = (void *) io.base + io_offset (port);
     179  
     180    *addr = val;
     181    __ia64_mf_a();
     182  }
     183  
     184  void
     185  _outl (unsigned int val, unsigned long int port)
     186  {
     187    volatile unsigned int *addr = (void *) io.base + io_offset (port);
     188  
     189    *addr = val;
     190    __ia64_mf_a();
     191  }
     192  
     193  weak_alias (_ioperm, ioperm);
     194  weak_alias (_iopl, iopl);
     195  weak_alias (_inb, inb);
     196  weak_alias (_inw, inw);
     197  weak_alias (_inl, inl);
     198  weak_alias (_outb, outb);
     199  weak_alias (_outw, outw);
     200  weak_alias (_outl, outl);