(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
alpha/
ioperm.c
       1  /* Copyright (C) 1992-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, the entire (E)ISA port space is mapped
      23     into the virtual address space at address io.base.  mprotect calls
      24     are then used to enable/disable access to ports.  Per page, there
      25     are PAGE_SIZE>>IO_SHIFT I/O ports (e.g., 256 ports on a Low Cost Alpha
      26     based system using 8KB pages).
      27  
      28     Keep in mind that this code should be able to run in a 32bit address
      29     space.  It is therefore unreasonable to expect mmap'ing the entire
      30     sparse address space would work (e.g., the Low Cost Alpha chip has an
      31     I/O address space that's 512MB large!).  */
      32  
      33  /* Make sure the ldbu/stb asms below are not expaneded to macros.  */
      34  #ifndef __alpha_bwx__
      35  asm(".arch ev56");
      36  #endif
      37  
      38  #include <errno.h>
      39  #include <fcntl.h>
      40  #include <stdio.h>
      41  #include <ctype.h>
      42  #include <stdlib.h>
      43  #include <string.h>
      44  #include <unistd.h>
      45  
      46  #include <sys/types.h>
      47  #include <sys/mman.h>
      48  #include <sys/io.h>
      49  
      50  #include <sysdep.h>
      51  #include <sys/syscall.h>
      52  
      53  #define PATH_ALPHA_SYSTYPE	"/etc/alpha_systype"
      54  #define PATH_CPUINFO		"/proc/cpuinfo"
      55  
      56  #define MAX_PORT	0x10000
      57  #define vip		volatile int *
      58  #define vuip		volatile unsigned int *
      59  #define vusp		volatile unsigned short *
      60  #define vucp		volatile unsigned char *
      61  
      62  #define JENSEN_IO_BASE		(0x300000000UL)
      63  #define JENSEN_SPARSE_MEM	(0x200000000UL)
      64  
      65  /* With respect to the I/O architecture, APECS and LCA are identical,
      66     so the following defines apply to LCA as well.  */
      67  #define APECS_IO_BASE		(0x1c0000000UL)
      68  #define APECS_SPARSE_MEM	(0x200000000UL)
      69  #define APECS_DENSE_MEM		(0x300000000UL)
      70  
      71  /* The same holds for CIA and PYXIS, except for PYXIS we prefer BWX.  */
      72  #define CIA_IO_BASE		(0x8580000000UL)
      73  #define CIA_SPARSE_MEM		(0x8000000000UL)
      74  #define CIA_DENSE_MEM		(0x8600000000UL)
      75  
      76  #define PYXIS_IO_BASE		(0x8900000000UL)
      77  #define PYXIS_DENSE_MEM		(0x8800000000UL)
      78  
      79  /* SABLE is EV4, GAMMA is EV5 */
      80  #define T2_IO_BASE		(0x3a0000000UL)
      81  #define T2_SPARSE_MEM		(0x200000000UL)
      82  #define T2_DENSE_MEM		(0x3c0000000UL)
      83  
      84  #define GAMMA_IO_BASE		(0x83a0000000UL)
      85  #define GAMMA_SPARSE_MEM	(0x8200000000UL)
      86  #define GAMMA_DENSE_MEM		(0x83c0000000UL)
      87  
      88  /* NOTE: these are hardwired to PCI bus 0 addresses!!! */
      89  #define MCPCIA_IO_BASE		(0xf980000000UL)
      90  #define MCPCIA_SPARSE_MEM	(0xf800000000UL)
      91  #define MCPCIA_DENSE_MEM	(0xf900000000UL)
      92  
      93  /* Tsunami and Irongate use the same offsets, at least for hose 0.  */
      94  #define TSUNAMI_IO_BASE		(0x801fc000000UL)
      95  #define TSUNAMI_DENSE_MEM	(0x80000000000UL)
      96  
      97  /* Polaris has SPARSE space, but we prefer to use only DENSE
      98     because of some idiosyncrasies in actually using SPARSE.  */
      99  #define POLARIS_IO_BASE		(0xf9fc000000UL)
     100  #define POLARIS_DENSE_MEM	(0xf900000000UL)
     101  
     102  typedef enum {
     103    IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2,
     104    IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS,
     105    IOSYS_CPUDEP, IOSYS_PCIDEP
     106  } iosys_t;
     107  
     108  typedef enum {
     109    IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE
     110  } ioswizzle_t;
     111  
     112  static struct io_system {
     113    unsigned long	int bus_memory_base;
     114    unsigned long	int sparse_bus_mem_base;
     115    unsigned long	int bus_io_base;
     116  } io_system[] = { /* NOTE! must match iosys_t enumeration */
     117  /* UNKNOWN */	{0, 0, 0},
     118  /* JENSEN */	{0, JENSEN_SPARSE_MEM, JENSEN_IO_BASE},
     119  /* APECS */	{APECS_DENSE_MEM, APECS_SPARSE_MEM, APECS_IO_BASE},
     120  /* CIA */	{CIA_DENSE_MEM, CIA_SPARSE_MEM, CIA_IO_BASE},
     121  /* PYXIS */	{PYXIS_DENSE_MEM, 0, PYXIS_IO_BASE},
     122  /* T2 */	{T2_DENSE_MEM, T2_SPARSE_MEM, T2_IO_BASE},
     123  /* TSUNAMI */	{TSUNAMI_DENSE_MEM, 0, TSUNAMI_IO_BASE},
     124  /* MCPCIA */	{MCPCIA_DENSE_MEM, MCPCIA_SPARSE_MEM, MCPCIA_IO_BASE},
     125  /* GAMMA */	{GAMMA_DENSE_MEM, GAMMA_SPARSE_MEM, GAMMA_IO_BASE},
     126  /* POLARIS */	{POLARIS_DENSE_MEM, 0, POLARIS_IO_BASE},
     127  /* CPUDEP */	{0, 0, 0}, /* for platforms dependent on CPU type */
     128  /* PCIDEP */	{0, 0, 0}, /* for platforms dependent on core logic */
     129  };
     130  
     131  static struct platform {
     132    const char	   *name;
     133    iosys_t	    io_sys;
     134  } platform[] = {
     135    {"Alcor",	IOSYS_CIA},
     136    {"Avanti",	IOSYS_APECS},
     137    {"Cabriolet",	IOSYS_APECS},
     138    {"EB164",	IOSYS_PCIDEP},
     139    {"EB64+",	IOSYS_APECS},
     140    {"EB66",	IOSYS_APECS},
     141    {"EB66P",	IOSYS_APECS},
     142    {"Jensen",	IOSYS_JENSEN},
     143    {"Miata",	IOSYS_PYXIS},
     144    {"Mikasa",	IOSYS_CPUDEP},
     145    {"Nautilus",	IOSYS_TSUNAMI},
     146    {"Noname",	IOSYS_APECS},
     147    {"Noritake",	IOSYS_CPUDEP},
     148    {"Rawhide",	IOSYS_MCPCIA},
     149    {"Ruffian",	IOSYS_PYXIS},
     150    {"Sable",	IOSYS_CPUDEP},
     151    {"Takara",	IOSYS_CIA},
     152    {"Tsunami",	IOSYS_TSUNAMI},
     153    {"XL",	IOSYS_APECS},
     154  };
     155  
     156  struct ioswtch {
     157    void		(*sethae)(unsigned long int addr);
     158    void		(*outb)(unsigned char b, unsigned long int port);
     159    void		(*outw)(unsigned short b, unsigned long int port);
     160    void		(*outl)(unsigned int b, unsigned long int port);
     161    unsigned int	(*inb)(unsigned long int port);
     162    unsigned int	(*inw)(unsigned long int port);
     163    unsigned int	(*inl)(unsigned long int port);
     164  };
     165  
     166  static struct {
     167    unsigned long int hae_cache;
     168    unsigned long int	base;
     169    struct ioswtch *	swp;
     170    unsigned long int	bus_memory_base;
     171    unsigned long int	sparse_bus_memory_base;
     172    unsigned long int	io_base;
     173    ioswizzle_t		swiz;
     174  } io;
     175  
     176  static inline void
     177  stb_mb(unsigned char val, unsigned long addr)
     178  {
     179    __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val));
     180  }
     181  
     182  static inline void
     183  stw_mb(unsigned short val, unsigned long addr)
     184  {
     185    __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val));
     186  }
     187  
     188  static inline void
     189  stl_mb(unsigned int val, unsigned long addr)
     190  {
     191    __asm__("stl %1,%0; mb" : "=m"(*(vip)addr) : "r"(val));
     192  }
     193  
     194  /* No need to examine error -- sethae never fails.  */
     195  static inline void
     196  __sethae(unsigned long value)
     197  {
     198    INLINE_SYSCALL_CALL (sethae, value);
     199  }
     200  
     201  extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which,
     202  			       unsigned long int __bus,
     203  			       unsigned long int __dfn);
     204  
     205  static inline unsigned long int
     206  port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size)
     207  {
     208    if (ioswiz == IOSWIZZLE_SPARSE)
     209      return io.base + (port << 5) + ((size - 1) << 3);
     210    else if (ioswiz == IOSWIZZLE_DENSE)
     211      return port + io.base;
     212    else
     213      return io.base + (port << 7) + ((size - 1) << 5);
     214  }
     215  
     216  static inline __attribute__((always_inline)) void
     217  inline_sethae (unsigned long int addr, ioswizzle_t ioswiz)
     218  {
     219    if (ioswiz == IOSWIZZLE_SPARSE)
     220      {
     221        unsigned long int msb;
     222  
     223        /* no need to set hae if msb is 0: */
     224        msb = addr & 0xf8000000;
     225        if (msb && msb != io.hae_cache)
     226  	{
     227  	  io.hae_cache = msb;
     228  	  __sethae (msb);
     229  	}
     230      }
     231    else if (ioswiz == IOSWIZZLE_JENSEN)
     232      {
     233        /* HAE on the Jensen is bits 31:25 shifted right.  */
     234        addr >>= 25;
     235        if (addr != io.hae_cache)
     236  	{
     237  	  io.hae_cache = addr;
     238  	  __sethae (addr);
     239  	}
     240      }
     241  }
     242  
     243  static inline void
     244  inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz)
     245  {
     246    unsigned int w;
     247    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
     248  
     249    asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
     250    stl_mb(w, addr);
     251  }
     252  
     253  
     254  static inline void
     255  inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz)
     256  {
     257    unsigned long w;
     258    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
     259  
     260    asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
     261    stl_mb(w, addr);
     262  }
     263  
     264  
     265  static inline void
     266  inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz)
     267  {
     268    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
     269  
     270    stl_mb(b, addr);
     271  }
     272  
     273  
     274  static inline unsigned int
     275  inline_inb (unsigned long int port, ioswizzle_t ioswiz)
     276  {
     277    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
     278    int result;
     279  
     280    result = *(vip) addr;
     281    result >>= (port & 3) * 8;
     282    return 0xffUL & result;
     283  }
     284  
     285  
     286  static inline unsigned int
     287  inline_inw (unsigned long int port, ioswizzle_t ioswiz)
     288  {
     289    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
     290    int result;
     291  
     292    result = *(vip) addr;
     293    result >>= (port & 3) * 8;
     294    return 0xffffUL & result;
     295  }
     296  
     297  
     298  static inline unsigned int
     299  inline_inl (unsigned long int port, ioswizzle_t ioswiz)
     300  {
     301    unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
     302  
     303    return *(vuip) addr;
     304  }
     305  
     306  /*
     307   * Now define the inline functions for CPUs supporting byte/word insns,
     308   * and whose core logic supports I/O space accesses utilizing them.
     309   *
     310   * These routines could be used by MIATA, for example, because it has
     311   * and EV56 plus PYXIS, but it currently uses SPARSE anyway. This is
     312   * also true of RX164 which used POLARIS, but we will choose to use
     313   * these routines in that case instead of SPARSE.
     314   *
     315   * These routines are necessary for TSUNAMI/TYPHOON based platforms,
     316   * which will have (at least) EV6.
     317   */
     318  
     319  static inline unsigned long int
     320  dense_port_to_cpu_addr (unsigned long int port)
     321  {
     322    return port + io.base;
     323  }
     324  
     325  static inline void
     326  inline_bwx_outb (unsigned char b, unsigned long int port)
     327  {
     328    unsigned long int addr = dense_port_to_cpu_addr (port);
     329    stb_mb (b, addr);
     330  }
     331  
     332  static inline void
     333  inline_bwx_outw (unsigned short int b, unsigned long int port)
     334  {
     335    unsigned long int addr = dense_port_to_cpu_addr (port);
     336    stw_mb (b, addr);
     337  }
     338  
     339  static inline void
     340  inline_bwx_outl (unsigned int b, unsigned long int port)
     341  {
     342    unsigned long int addr = dense_port_to_cpu_addr (port);
     343    stl_mb (b, addr);
     344  }
     345  
     346  static inline unsigned int
     347  inline_bwx_inb (unsigned long int port)
     348  {
     349    unsigned long int addr = dense_port_to_cpu_addr (port);
     350    unsigned char r;
     351  
     352    __asm__ ("ldbu %0,%1" : "=r"(r) : "m"(*(vucp)addr));
     353    return r;
     354  }
     355  
     356  static inline unsigned int
     357  inline_bwx_inw (unsigned long int port)
     358  {
     359    unsigned long int addr = dense_port_to_cpu_addr (port);
     360    unsigned short r;
     361  
     362    __asm__ ("ldwu %0,%1" : "=r"(r) : "m"(*(vusp)addr));
     363    return r;
     364  }
     365  
     366  static inline unsigned int
     367  inline_bwx_inl (unsigned long int port)
     368  {
     369    unsigned long int addr = dense_port_to_cpu_addr (port);
     370  
     371    return *(vuip) addr;
     372  }
     373  
     374  /* macros to define routines with appropriate names and functions */
     375  
     376  /* these do either SPARSE or JENSEN swizzle */
     377  
     378  #define DCL_SETHAE(name, ioswiz)                        \
     379  static void                                             \
     380  name##_sethae (unsigned long int addr)                  \
     381  {                                                       \
     382    inline_sethae (addr, IOSWIZZLE_##ioswiz);             \
     383  }
     384  
     385  #define DCL_OUT(name, func, type, ioswiz)		\
     386  static void						\
     387  name##_##func (unsigned type b, unsigned long int addr)	\
     388  {							\
     389    inline_##func (b, addr, IOSWIZZLE_##ioswiz);		\
     390  }
     391  
     392  #define DCL_IN(name, func, ioswiz)			\
     393  static unsigned int					\
     394  name##_##func (unsigned long int addr)			\
     395  {							\
     396    return inline_##func (addr, IOSWIZZLE_##ioswiz);	\
     397  }
     398  
     399  /* these do DENSE, so no swizzle is needed */
     400  
     401  #define DCL_OUT_BWX(name, func, type)			\
     402  static void						\
     403  name##_##func (unsigned type b, unsigned long int addr)	\
     404  {							\
     405    inline_bwx_##func (b, addr);				\
     406  }
     407  
     408  #define DCL_IN_BWX(name, func)				\
     409  static unsigned int					\
     410  name##_##func (unsigned long int addr)			\
     411  {							\
     412    return inline_bwx_##func (addr);			\
     413  }
     414  
     415  /* now declare/define the necessary routines */
     416  
     417  DCL_SETHAE(jensen, JENSEN)
     418  DCL_OUT(jensen, outb, char,  JENSEN)
     419  DCL_OUT(jensen, outw, short int, JENSEN)
     420  DCL_OUT(jensen, outl, int,   JENSEN)
     421  DCL_IN(jensen, inb, JENSEN)
     422  DCL_IN(jensen, inw, JENSEN)
     423  DCL_IN(jensen, inl, JENSEN)
     424  
     425  DCL_SETHAE(sparse, SPARSE)
     426  DCL_OUT(sparse, outb, char,  SPARSE)
     427  DCL_OUT(sparse, outw, short int, SPARSE)
     428  DCL_OUT(sparse, outl, int,   SPARSE)
     429  DCL_IN(sparse, inb, SPARSE)
     430  DCL_IN(sparse, inw, SPARSE)
     431  DCL_IN(sparse, inl, SPARSE)
     432  
     433  DCL_SETHAE(dense, DENSE)
     434  DCL_OUT_BWX(dense, outb, char)
     435  DCL_OUT_BWX(dense, outw, short int)
     436  DCL_OUT_BWX(dense, outl, int)
     437  DCL_IN_BWX(dense, inb)
     438  DCL_IN_BWX(dense, inw)
     439  DCL_IN_BWX(dense, inl)
     440  
     441  /* define the "swizzle" switch */
     442  static struct ioswtch ioswtch[] = {
     443    {
     444      jensen_sethae,
     445      jensen_outb, jensen_outw, jensen_outl,
     446      jensen_inb, jensen_inw, jensen_inl
     447    },
     448    {
     449      sparse_sethae,
     450      sparse_outb, sparse_outw, sparse_outl,
     451      sparse_inb, sparse_inw, sparse_inl
     452    },
     453    {
     454      dense_sethae,
     455      dense_outb, dense_outw, dense_outl,
     456      dense_inb, dense_inw, dense_inl
     457    }
     458  };
     459  
     460  #undef DEBUG_IOPERM
     461  
     462  /* Routine to process the /proc/cpuinfo information into the fields
     463     that are required for correctly determining the platform parameters.  */
     464  
     465  struct cpuinfo_data
     466  {
     467    char systype[256];		/* system type field */
     468    char sysvari[256];		/* system variation field */
     469    char cpumodel[256];		/* cpu model field */
     470  };
     471  
     472  static inline int
     473  process_cpuinfo(struct cpuinfo_data *data)
     474  {
     475    int got_type, got_vari, got_model;
     476    char dummy[256];
     477    FILE * fp;
     478    int n;
     479  
     480    data->systype[0] = 0;
     481    data->sysvari[0] = 0;
     482    data->cpumodel[0] = 0;
     483  
     484    /* If there's an /etc/alpha_systype link, we're intending to override
     485       whatever's in /proc/cpuinfo.  */
     486    n = __readlink (PATH_ALPHA_SYSTYPE, data->systype, 256 - 1);
     487    if (n > 0)
     488      {
     489        data->systype[n] = '\0';
     490        return 1;
     491      }
     492  
     493    fp = fopen (PATH_CPUINFO, "rce");
     494    if (!fp)
     495      return 0;
     496  
     497    got_type = got_vari = got_model = 0;
     498  
     499    while (1)
     500      {
     501        if (fgets_unlocked (dummy, 256, fp) == NULL)
     502  	break;
     503        if (!got_type
     504  	  && sscanf (dummy, "system type : %256[^\n]\n", data->systype) == 1)
     505  	got_type = 1;
     506        if (!got_vari
     507  	  && (sscanf (dummy, "system variation : %256[^\n]\n", data->sysvari)
     508  	      == 1))
     509  	got_vari = 1;
     510        if (!got_model
     511  	  && sscanf (dummy, "cpu model : %256[^\n]\n", data->cpumodel) == 1)
     512  	got_model = 1;
     513      }
     514  
     515    fclose (fp);
     516  
     517  #ifdef DEBUG_IOPERM
     518    fprintf(stderr, "system type: `%s'\n", data->systype);
     519    fprintf(stderr, "system vari: `%s'\n", data->sysvari);
     520    fprintf(stderr, "cpu model: `%s'\n", data->cpumodel);
     521  #endif
     522  
     523    return got_type + got_vari + got_model;
     524  }
     525  
     526  
     527  /*
     528   * Initialize I/O system.
     529   */
     530  static int
     531  init_iosys (void)
     532  {
     533    long addr;
     534    int i, olderrno = errno;
     535    struct cpuinfo_data data;
     536  
     537    /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99.  */
     538  
     539    addr = __pciconfig_iobase (IOBASE_DENSE_MEM, 0, 0);
     540    if (addr != -1)
     541      {
     542        ioswizzle_t io_swiz;
     543  
     544        if (addr == 0)
     545          {
     546  	  /* Only Jensen doesn't have dense mem space.  */
     547  	  io.sparse_bus_memory_base
     548  	    = io_system[IOSYS_JENSEN].sparse_bus_mem_base;
     549  	  io.io_base = io_system[IOSYS_JENSEN].bus_io_base;
     550  	  io_swiz = IOSWIZZLE_JENSEN;
     551  	}
     552        else
     553  	{
     554  	  io.bus_memory_base = addr;
     555  
     556  	  addr = __pciconfig_iobase (IOBASE_DENSE_IO, 0, 0);
     557  	  if (addr != 0)
     558  	    {
     559  	      /* The X server uses _bus_base_sparse == 0 to know that
     560  		 BWX access are supported to dense mem space.  This is
     561  		 true of every system that supports dense io space, so
     562  	         never fill in io.sparse_bus_memory_base in this case.  */
     563  	      io_swiz = IOSWIZZLE_DENSE;
     564                io.io_base = addr;
     565  	    }
     566  	  else
     567  	    {
     568  	      io.sparse_bus_memory_base
     569  		= __pciconfig_iobase (IOBASE_SPARSE_MEM, 0, 0);
     570  	      io.io_base = __pciconfig_iobase (IOBASE_SPARSE_IO, 0, 0);
     571  	      io_swiz = IOSWIZZLE_SPARSE;
     572  	    }
     573  	}
     574  
     575        io.swiz = io_swiz;
     576        io.swp = &ioswtch[io_swiz];
     577  
     578        return 0;
     579      }
     580  
     581    /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo.  */
     582  
     583    if (process_cpuinfo(&data) == 0)
     584      {
     585        /* This can happen if the format of /proc/cpuinfo changes.  */
     586        fprintf (stderr,
     587  	       "ioperm.init_iosys: Unable to determine system type.\n"
     588  	       "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
     589        __set_errno (ENODEV);
     590        return -1;
     591      }
     592  
     593    /* Translate systype name into i/o system.  */
     594    for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
     595      {
     596        if (strcmp (platform[i].name, data.systype) == 0)
     597  	{
     598  	  iosys_t io_sys = platform[i].io_sys;
     599  
     600  	  /* Some platforms can have either EV4 or EV5 CPUs.  */
     601  	  if (io_sys == IOSYS_CPUDEP)
     602  	    {
     603  	      /* SABLE or MIKASA or NORITAKE so far.  */
     604  	      if (strcmp (platform[i].name, "Sable") == 0)
     605  		{
     606  		  if (strncmp (data.cpumodel, "EV4", 3) == 0)
     607  		    io_sys = IOSYS_T2;
     608  		  else if (strncmp (data.cpumodel, "EV5", 3) == 0)
     609  		    io_sys = IOSYS_GAMMA;
     610  		}
     611  	      else
     612  		{
     613  		  /* This covers MIKASA/NORITAKE.  */
     614  		  if (strncmp (data.cpumodel, "EV4", 3) == 0)
     615  		    io_sys = IOSYS_APECS;
     616  		  else if (strncmp (data.cpumodel, "EV5", 3) == 0)
     617  		    io_sys = IOSYS_CIA;
     618  		}
     619  	      if (io_sys == IOSYS_CPUDEP)
     620  		{
     621  		  /* This can happen if the format of /proc/cpuinfo changes.*/
     622  		  fprintf (stderr, "ioperm.init_iosys: Unable to determine"
     623  			   " CPU model.\n");
     624  		  __set_errno (ENODEV);
     625  		  return -1;
     626  		}
     627  	    }
     628  	  /* Some platforms can have different core logic chipsets */
     629  	  if (io_sys == IOSYS_PCIDEP)
     630  	    {
     631  	      /* EB164 so far */
     632  	      if (strcmp (data.systype, "EB164") == 0)
     633  		{
     634  		  if (strncmp (data.sysvari, "RX164", 5) == 0)
     635  		    io_sys = IOSYS_POLARIS;
     636  		  else if (strncmp (data.sysvari, "LX164", 5) == 0
     637  			   || strncmp (data.sysvari, "SX164", 5) == 0)
     638  		    io_sys = IOSYS_PYXIS;
     639  		  else
     640  		    io_sys = IOSYS_CIA;
     641  		}
     642  	      if (io_sys == IOSYS_PCIDEP)
     643  		{
     644  		  /* This can happen if the format of /proc/cpuinfo changes.*/
     645  		  fprintf (stderr, "ioperm.init_iosys: Unable to determine"
     646  			   " core logic chipset.\n");
     647  		  __set_errno (ENODEV);
     648  		  return -1;
     649  		}
     650  	    }
     651  	  io.bus_memory_base = io_system[io_sys].bus_memory_base;
     652  	  io.sparse_bus_memory_base = io_system[io_sys].sparse_bus_mem_base;
     653  	  io.io_base = io_system[io_sys].bus_io_base;
     654  
     655  	  if (io_sys == IOSYS_JENSEN)
     656  	    io.swiz = IOSWIZZLE_JENSEN;
     657  	  else if (io_sys == IOSYS_TSUNAMI
     658  		   || io_sys == IOSYS_POLARIS
     659  		   || io_sys == IOSYS_PYXIS)
     660  	    io.swiz = IOSWIZZLE_DENSE;
     661  	  else
     662  	    io.swiz = IOSWIZZLE_SPARSE;
     663  	  io.swp = &ioswtch[io.swiz];
     664  
     665  	  __set_errno (olderrno);
     666  	  return 0;
     667  	}
     668      }
     669  
     670    __set_errno (ENODEV);
     671    fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n"
     672  	  "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
     673    return -1;
     674  }
     675  
     676  
     677  int
     678  _ioperm (unsigned long int from, unsigned long int num, int turn_on)
     679  {
     680    unsigned long int addr, len, pagesize = __getpagesize();
     681    int prot;
     682  
     683    if (!io.swp && init_iosys() < 0)
     684      {
     685  #ifdef DEBUG_IOPERM
     686        fprintf(stderr, "ioperm: init_iosys() failed (%m)\n");
     687  #endif
     688        return -1;
     689      }
     690  
     691    /* This test isn't as silly as it may look like; consider overflows! */
     692    if (from >= MAX_PORT || from + num > MAX_PORT)
     693      {
     694        __set_errno (EINVAL);
     695  #ifdef DEBUG_IOPERM
     696        fprintf(stderr, "ioperm: from/num out of range\n");
     697  #endif
     698        return -1;
     699      }
     700  
     701  #ifdef DEBUG_IOPERM
     702    fprintf(stderr, "ioperm: turn_on %d io.base %ld\n", turn_on, io.base);
     703  #endif
     704  
     705    if (turn_on)
     706      {
     707        if (!io.base)
     708  	{
     709  	  int fd;
     710  
     711  	  io.hae_cache = 0;
     712  	  if (io.swiz != IOSWIZZLE_DENSE)
     713  	    {
     714  	      /* Synchronize with hw.  */
     715  	      __sethae (0);
     716  	    }
     717  
     718  	  fd = __open ("/dev/mem", O_RDWR);
     719  	  if (fd < 0)
     720  	    {
     721  #ifdef DEBUG_IOPERM
     722  	      fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n");
     723  #endif
     724  	      return -1;
     725  	    }
     726  
     727  	  addr = port_to_cpu_addr (0, io.swiz, 1);
     728  	  len = port_to_cpu_addr (MAX_PORT, io.swiz, 1) - addr;
     729  	  io.base =
     730  	    (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED,
     731  					fd, io.io_base);
     732  	  __close (fd);
     733  #ifdef DEBUG_IOPERM
     734  	  fprintf(stderr, "ioperm: mmap of len 0x%lx  returned 0x%lx\n",
     735  		  len, io.base);
     736  #endif
     737  	  if ((long) io.base == -1)
     738  	    return -1;
     739  	}
     740        prot = PROT_READ | PROT_WRITE;
     741      }
     742    else
     743      {
     744        if (!io.base)
     745  	return 0;	/* never was turned on... */
     746  
     747        /* turnoff access to relevant pages: */
     748        prot = PROT_NONE;
     749      }
     750    addr = port_to_cpu_addr (from, io.swiz, 1);
     751    addr &= ~(pagesize - 1);
     752    len = port_to_cpu_addr (from + num, io.swiz, 1) - addr;
     753    return __mprotect ((void *) addr, len, prot);
     754  }
     755  
     756  
     757  int
     758  _iopl (int level)
     759  {
     760    switch (level)
     761      {
     762      case 0:
     763        return 0;
     764  
     765      case 1: case 2: case 3:
     766        return _ioperm (0, MAX_PORT, 1);
     767  
     768      default:
     769        __set_errno (EINVAL);
     770        return -1;
     771      }
     772  }
     773  
     774  
     775  void
     776  _sethae (unsigned long int addr)
     777  {
     778    if (!io.swp && init_iosys () < 0)
     779      return;
     780  
     781    io.swp->sethae (addr);
     782  }
     783  
     784  
     785  void
     786  _outb (unsigned char b, unsigned long int port)
     787  {
     788    if (port >= MAX_PORT)
     789      return;
     790  
     791    io.swp->outb (b, port);
     792  }
     793  
     794  
     795  void
     796  _outw (unsigned short b, unsigned long int port)
     797  {
     798    if (port >= MAX_PORT)
     799      return;
     800  
     801    io.swp->outw (b, port);
     802  }
     803  
     804  
     805  void
     806  _outl (unsigned int b, unsigned long int port)
     807  {
     808    if (port >= MAX_PORT)
     809      return;
     810  
     811    io.swp->outl (b, port);
     812  }
     813  
     814  
     815  unsigned int
     816  _inb (unsigned long int port)
     817  {
     818    return io.swp->inb (port);
     819  }
     820  
     821  
     822  unsigned int
     823  _inw (unsigned long int port)
     824  {
     825    return io.swp->inw (port);
     826  }
     827  
     828  
     829  unsigned int
     830  _inl (unsigned long int port)
     831  {
     832    return io.swp->inl (port);
     833  }
     834  
     835  
     836  unsigned long int
     837  _bus_base(void)
     838  {
     839    if (!io.swp && init_iosys () < 0)
     840      return -1;
     841    return io.bus_memory_base;
     842  }
     843  
     844  unsigned long int
     845  _bus_base_sparse(void)
     846  {
     847    if (!io.swp && init_iosys () < 0)
     848      return -1;
     849    return io.sparse_bus_memory_base;
     850  }
     851  
     852  int
     853  _hae_shift(void)
     854  {
     855    if (!io.swp && init_iosys () < 0)
     856      return -1;
     857    if (io.swiz == IOSWIZZLE_JENSEN)
     858      return 7;
     859    if (io.swiz == IOSWIZZLE_SPARSE)
     860      return 5;
     861    return 0;
     862  }
     863  
     864  weak_alias (_sethae, sethae);
     865  weak_alias (_ioperm, ioperm);
     866  weak_alias (_iopl, iopl);
     867  weak_alias (_inb, inb);
     868  weak_alias (_inw, inw);
     869  weak_alias (_inl, inl);
     870  weak_alias (_outb, outb);
     871  weak_alias (_outw, outw);
     872  weak_alias (_outl, outl);
     873  weak_alias (_bus_base, bus_base);
     874  weak_alias (_bus_base_sparse, bus_base_sparse);
     875  weak_alias (_hae_shift, hae_shift);