diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | sysdeps/gnu/errlist.c | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/Versions | 7 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/ioperm.c | 271 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/sys/io.h | 48 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/syscalls.list | 30 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/sysdep.h | 46 |
7 files changed, 388 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog index 12acbe8181..5e6a448fa9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +1998-12-20 Philip Blundell <philb@gnu.org> + + * sysdeps/unix/sysv/linux/arm/sysdep.h (INLINE_SYSCALL): Add + implementation. + * sysdeps/unix/sysv/linux/arm/syscalls.list: Remove wrappers for + now-inlined calls. + +1998-12-22 Philip Blundell <pb@nexus.co.uk> + + * sysdeps/unix/sysv/linux/arm/ioperm.c: New file. + Implementation of inb, outb etc for ARM systems. + * sysdeps/unix/sysv/linux/arm/sys/io.h: Likewise. + * sysdeps/unix/sysv/linux/arm/Versions: Add appropriate + entries for the above. + 1998-12-21 Ulrich Drepper <drepper@cygnus.com> * nss/db-Makefile (shadow.db): Create file with correct protections. diff --git a/sysdeps/gnu/errlist.c b/sysdeps/gnu/errlist.c index 2f81a7d786..b5f9486eae 100644 --- a/sysdeps/gnu/errlist.c +++ b/sysdeps/gnu/errlist.c @@ -495,7 +495,7 @@ TRANS @c This can probably happen in a GNU system when using NFS. */ #ifdef EDQUOT /* TRANS The user's disk quota was exceeded. */ - [ERR_REMAP (EDQUOT)] = N_("Disc quota exceeded"), + [ERR_REMAP (EDQUOT)] = N_("Disk quota exceeded"), #endif #ifdef ESTALE /* diff --git a/sysdeps/unix/sysv/linux/arm/Versions b/sysdeps/unix/sysv/linux/arm/Versions new file mode 100644 index 0000000000..3a412cc3a3 --- /dev/null +++ b/sysdeps/unix/sysv/linux/arm/Versions @@ -0,0 +1,7 @@ +libc { + GLIBC_2.1 { + ioperm; iopl; + inb; inw; inl; + outb; outw; outl; + } +} diff --git a/sysdeps/unix/sysv/linux/arm/ioperm.c b/sysdeps/unix/sysv/linux/arm/ioperm.c new file mode 100644 index 0000000000..551fc97d0c --- /dev/null +++ b/sysdeps/unix/sysv/linux/arm/ioperm.c @@ -0,0 +1,271 @@ +/* Copyright (C) 1998 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) +{ + if (port >= MAX_PORT) + return; + + *((volatile unsigned char *)(IO_ADDR (port))) = b; +} + + +void +_outw (unsigned short b, unsigned long int port) +{ + if (port >= MAX_PORT) + return; + + *((volatile unsigned short *)(IO_ADDR (port))) = b; +} + + +void +_outl (unsigned int b, unsigned long int port) +{ + if (port >= MAX_PORT) + return; + + *((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); diff --git a/sysdeps/unix/sysv/linux/arm/sys/io.h b/sysdeps/unix/sysv/linux/arm/sys/io.h new file mode 100644 index 0000000000..9f9eebc6fb --- /dev/null +++ b/sysdeps/unix/sysv/linux/arm/sys/io.h @@ -0,0 +1,48 @@ +/* Copyright (C) 1996, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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. */ + +#ifndef _SYS_IO_H + +#define _SYS_IO_H 1 +#include <features.h> + +__BEGIN_DECLS + +/* If TURN_ON is TRUE, request for permission to do direct i/o on the + port numbers in the range [FROM,FROM+NUM-1]. Otherwise, turn I/O + permission off for that range. This call requires root privileges. */ +extern int ioperm __P ((unsigned long int __from, unsigned long int __num, + int __turn_on)); + +/* Set the I/O privilege level to LEVEL. If LEVEL is nonzero, + permission to access any I/O port is granted. This call requires + root privileges. */ +extern int iopl __P ((int __level)); + +/* The functions that actually perform reads and writes. */ +extern unsigned char inb (unsigned long port); +extern unsigned short inw (unsigned long port); +extern unsigned long inl (unsigned long port); + +extern void outb (unsigned char value, unsigned long port); +extern void outw (unsigned short value, unsigned long port); +extern void outl (unsigned long value, unsigned long port); + +__END_DECLS + +#endif /* _SYS_IO_H */ diff --git a/sysdeps/unix/sysv/linux/arm/syscalls.list b/sysdeps/unix/sysv/linux/arm/syscalls.list index 6f332ce873..08839db952 100644 --- a/sysdeps/unix/sysv/linux/arm/syscalls.list +++ b/sysdeps/unix/sysv/linux/arm/syscalls.list @@ -13,33 +13,3 @@ s_setreuid setreuid setreuid 2 __syscall_setreuid s_setuid setuid setuid 1 __syscall_setuid syscall - syscall 5 syscall vm86 - vm86 1 __vm86 vm86 - -# System calls with wrappers. -rt_sigaction - rt_sigaction 4 __syscall_rt_sigaction -rt_sigpending - rt_sigpending 2 __syscall_rt_sigpending -rt_sigprocmask - rt_sigprocmask 4 __syscall_rt_sigprocmask -rt_sigqueueinfo - rt_sigqueueinfo 3 __syscall_rt_sigqueueinfo -rt_sigsuspend - rt_sigsuspend 2 __syscall_rt_sigsuspend -rt_sigtimedwait - rt_sigtimedwait 4 __syscall_rt_sigtimedwait -s_getcwd getcwd getcwd 2 __syscall_getcwd -s_getdents getdents getdents 3 __syscall_getdents -s_getpriority getpriority getpriority 2 __syscall_getpriority -s_getresgid getresgid getresgid 3 __syscall_getresgid -s_getresuid getresuid getresuid 3 __syscall_getresuid -s_poll poll poll 3 __syscall_poll -s_pread64 pread64 pread 5 __syscall_pread -s_ptrace ptrace ptrace 4 __syscall_ptrace -s_pwrite64 pwrite64 pwrite 5 __syscall_pwrite -s_reboot reboot reboot 3 __syscall_reboot -s_sigaction sigaction sigaction 3 __syscall_sigaction -s_sigpending sigpending sigpending 1 __syscall_sigpending -s_sigprocmask sigprocmask sigprocmask 3 __syscall_sigprocmask -s_sigsuspend sigsuspend sigsuspend 3 __syscall_sigsuspend -s_sysctl sysctl _sysctl 1 __syscall__sysctl -s_ustat ustat ustat 2 __syscall_ustat -sys_fstat fxstat fstat 2 __syscall_fstat -sys_lstat lxstat lstat 2 __syscall_lstat -sys_mknod xmknod mknod 3 __syscall_mknod -sys_readv readv readv 3 __syscall_readv -sys_stat xstat stat 2 __syscall_stat -sys_writev writev writev 3 __syscall_writev diff --git a/sysdeps/unix/sysv/linux/arm/sysdep.h b/sysdeps/unix/sysv/linux/arm/sysdep.h index 5972abaa9a..d7e28220a7 100644 --- a/sysdeps/unix/sysv/linux/arm/sysdep.h +++ b/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -104,6 +104,52 @@ #define UNDOARGS_4 /* nothing */ #define UNDOARGS_5 ldr r4, [sp]; +#else /* not __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + register int _a1 asm ("a1"); \ + LOAD_ARGS_##nr (args) \ + asm volatile ("swi %1" \ + : "=r" (_a1) \ + : "i" (SYS_ify(name)) ASM_ARGS_##nr \ + : "a1"); \ + _sys_result = _a1; \ + } \ + if (_sys_result >= (unsigned int) -4095) \ + { \ + __set_errno (-_sys_result); \ + _sys_result = (unsigned int) -1; \ + } \ + (int) _sys_result; }) + +#define LOAD_ARGS_0() +#define ASM_ARGS_0 +#define LOAD_ARGS_1(a1) \ + _a1 = (int) (a1); \ + LOAD_ARGS_0 () +#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) +#define LOAD_ARGS_2(a1, a2) \ + register int _a2 asm ("a2") = (int) (a2); \ + LOAD_ARGS_1 (a1) +#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) +#define LOAD_ARGS_3(a1, a2, a3) \ + register int _a3 asm ("a3") = (int) (a3); \ + LOAD_ARGS_2 (a1, a2) +#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) +#define LOAD_ARGS_4(a1, a2, a3, a4) \ + register int _a4 asm ("a4") = (int) (a4); \ + LOAD_ARGS_3 (a1, a2, a3) +#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) +#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ + register int _v1 asm ("v1") = (int) (a5); \ + LOAD_ARGS_4 (a1, a2, a3, a4) +#define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) + #endif /* __ASSEMBLER__ */ #endif /* linux/arm/sysdep.h */ |