mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	1999-04-12 Philip Blundell <philb@gnu.org> * elf/elf.h: Update ARM definitions to match current gas2. * sysdeps/arm/bits/endian.h: Support big endian operation. * sysdeps/unix/sysv/linux/arm/ioperm.c (_outw, _outb, _outl): Don't bother range checking the port number. * sysdeps/unix/sysv/linux/arm/vfork.S: New file. * sysdeps/unix/sysv/linux/arm/sysdep.h (INLINE_SYSCALL): Include the syscall name in assembler output for ease of debugging. * sysdeps/unix/sysv/linux/arm/sigaction.c: Don't rely on undefined compiler behaviour. * sysdeps/unix/sysv/linux/arm/sigrestorer.S: New file. * sysdeps/unix/sysv/linux/arm/Makefile [$(subdir) = signal] (sysdep_routines): Add sigrestorer. * string/tester.c (test_strcpy): Add new tests for unaligned arguments. * sysdeps/arm/bits/string.h: Delete inline implementations of strcpy and stpcpy.
		
			
				
	
	
		
			263 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
|    Contributed by Phil Blundell, based on the Alpha version by
 | |
|    David Mosberger.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Library General Public License as
 | |
|    published by the Free Software Foundation; either version 2 of the
 | |
|    License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Library General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Library General Public
 | |
|    License along with the GNU C Library; see the file COPYING.LIB.  If not,
 | |
|    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | |
|    Boston, MA 02111-1307, USA.  */
 | |
| 
 | |
| /* I/O port access on the ARM is something of a fiction.  What we do is to
 | |
|    map an appropriate area of /dev/mem into user space so that a program
 | |
|    can blast away at the hardware in such a way as to generate I/O cycles
 | |
|    on the bus.  To insulate user code from dependencies on particular
 | |
|    hardware we don't allow calls to inb() and friends to be inlined, but
 | |
|    force them to come through code in here every time.  Performance-critical
 | |
|    registers tend to be memory mapped these days so this should be no big
 | |
|    problem.  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <stdio.h>
 | |
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/mman.h>
 | |
| 
 | |
| #include <asm/page.h>
 | |
| 
 | |
| #define PATH_ARM_SYSTYPE	"/etc/arm_systype"
 | |
| #define PATH_CPUINFO		"/proc/cpuinfo"
 | |
| 
 | |
| #define MAX_PORT	0x10000
 | |
| 
 | |
| static struct {
 | |
|   unsigned long int	base;
 | |
|   unsigned long int	io_base;
 | |
|   unsigned int		shift;
 | |
|   unsigned int		initdone;	/* since all the above could be 0 */
 | |
| } io;
 | |
| 
 | |
| #define IO_BASE_FOOTBRIDGE	0x7c000000
 | |
| #define IO_SHIFT_FOOTBRIDGE	0
 | |
| 
 | |
| static struct platform {
 | |
|   const char		*name;
 | |
|   unsigned long int	io_base;
 | |
|   unsigned int		shift;
 | |
| } platform[] = {
 | |
|   /* All currently supported platforms are in fact the same. :-)  */
 | |
|   {"Chalice-CATS",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
 | |
|   {"DEC-EBSA285",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
 | |
|   {"Corel-NetWinder",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
 | |
| };
 | |
| 
 | |
| #define IO_ADDR(port)	(io.base + ((port) << io.shift))
 | |
| 
 | |
| /*
 | |
|  * Initialize I/O system.  To determine what I/O system we're dealing
 | |
|  * with, we first try to read the value of symlink PATH_ARM_SYSTYPE,
 | |
|  * if that fails, we lookup the "system type" field in /proc/cpuinfo.
 | |
|  * If that fails as well, we give up.  Other possible options might be
 | |
|  * to look at the ELF auxiliary vector or to add a special system call
 | |
|  * but there is probably no point.
 | |
|  *
 | |
|  * If the value received from PATH_ARM_SYSTYPE begins with a number,
 | |
|  * assume this is a previously unsupported system and the values encode,
 | |
|  * in order, "<io_base>,<port_shift>".
 | |
|  */
 | |
| 
 | |
| static int
 | |
| init_iosys (void)
 | |
| {
 | |
|   char systype[256];
 | |
|   int i, n;
 | |
| 
 | |
|   n = readlink (PATH_ARM_SYSTYPE, systype, sizeof (systype) - 1);
 | |
|   if (n > 0)
 | |
|     {
 | |
|       systype[n] = '\0';
 | |
|       if (isdigit (systype[0]))
 | |
| 	{
 | |
| 	  if (sscanf (systype, "%li,%i", &io.io_base, &io.shift) == 2)
 | |
| 	    {
 | |
| 	      io.initdone = 1;
 | |
| 	      return 0;
 | |
| 	    }
 | |
| 	  /* else we're likely going to fail with the system match below */
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       FILE * fp;
 | |
| 
 | |
|       fp = fopen (PATH_CPUINFO, "r");
 | |
|       if (!fp)
 | |
| 	return -1;
 | |
|       while ((n = fscanf (fp, "Hardware\t: %256[^\n]\n", systype))
 | |
| 	     != EOF)
 | |
| 	{
 | |
| 	  if (n == 1)
 | |
| 	    break;
 | |
| 	  else
 | |
| 	    fgets (systype, 256, fp);
 | |
| 	}
 | |
|       fclose (fp);
 | |
| 
 | |
|       if (n == EOF)
 | |
| 	{
 | |
| 	  /* this can happen if the format of /proc/cpuinfo changes...  */
 | |
| 	  fprintf (stderr,
 | |
| 		   "ioperm: Unable to determine system type.\n"
 | |
| 		   "\t(May need " PATH_ARM_SYSTYPE " symlink?)\n");
 | |
| 	  __set_errno (ENODEV);
 | |
| 	  return -1;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* translate systype name into i/o system: */
 | |
|   for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
 | |
|     {
 | |
|       if (strcmp (platform[i].name, systype) == 0)
 | |
| 	{
 | |
| 	  io.shift = platform[i].shift;
 | |
| 	  io.io_base = platform[i].io_base;
 | |
| 	  io.initdone = 1;
 | |
| 	  return 0;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* systype is not a known platform name... */
 | |
|   __set_errno (EINVAL);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| _ioperm (unsigned long int from, unsigned long int num, int turn_on)
 | |
| {
 | |
|   unsigned long int addr, len;
 | |
|   int prot;
 | |
| 
 | |
|   if (!io.initdone && init_iosys () < 0)
 | |
|     return -1;
 | |
| 
 | |
|   /* this test isn't as silly as it may look like; consider overflows! */
 | |
|   if (from >= MAX_PORT || from + num > MAX_PORT)
 | |
|     {
 | |
|       __set_errno (EINVAL);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   if (turn_on)
 | |
|     {
 | |
|       if (! io.base)
 | |
| 	{
 | |
| 	  int fd;
 | |
| 
 | |
| 	  fd = open ("/dev/mem", O_RDWR);
 | |
| 	  if (fd < 0)
 | |
| 	    return -1;
 | |
| 
 | |
| 	  io.base =
 | |
| 	    (unsigned long int) __mmap (0, MAX_PORT << io.shift, PROT_NONE, 
 | |
| 					MAP_SHARED, fd, io.io_base);
 | |
| 	  close (fd);
 | |
| 	  if ((long) io.base == -1)
 | |
| 	    return -1;
 | |
| 	}
 | |
|       prot = PROT_READ | PROT_WRITE;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (!io.base)
 | |
| 	return 0;	/* never was turned on... */
 | |
| 
 | |
|       /* turnoff access to relevant pages: */
 | |
|       prot = PROT_NONE;
 | |
|     }
 | |
|   addr = (io.base + (from << io.shift)) & PAGE_MASK;
 | |
|   len = num << io.shift;
 | |
|   return mprotect ((void *) addr, len, prot);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _iopl (unsigned int level)
 | |
| {
 | |
|     if (level > 3)
 | |
|       {
 | |
| 	__set_errno (EINVAL);
 | |
| 	return -1;
 | |
|       }
 | |
|     if (level)
 | |
|       {
 | |
| 	return _ioperm (0, MAX_PORT, 1);
 | |
|       }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| _outb (unsigned char b, unsigned long int port)
 | |
| {
 | |
|   *((volatile unsigned char *)(IO_ADDR (port))) = b;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| _outw (unsigned short b, unsigned long int port)
 | |
| {
 | |
|   *((volatile unsigned short *)(IO_ADDR (port))) = b;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| _outl (unsigned int b, unsigned long int port)
 | |
| {
 | |
|   *((volatile unsigned long *)(IO_ADDR (port))) = b;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned int
 | |
| _inb (unsigned long int port)
 | |
| {
 | |
|   return *((volatile unsigned char *)(IO_ADDR (port)));
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned int
 | |
| _inw (unsigned long int port)
 | |
| {
 | |
|   return *((volatile unsigned short *)(IO_ADDR (port)));
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned int
 | |
| _inl (unsigned long int port)
 | |
| {
 | |
|   return *((volatile unsigned long *)(IO_ADDR (port)));
 | |
| }
 | |
| 
 | |
| weak_alias (_ioperm, ioperm);
 | |
| weak_alias (_iopl, iopl);
 | |
| weak_alias (_inb, inb);
 | |
| weak_alias (_inw, inw);
 | |
| weak_alias (_inl, inl);
 | |
| weak_alias (_outb, outb);
 | |
| weak_alias (_outw, outw);
 | |
| weak_alias (_outl, outl);
 |