aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/mips
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-12-22 20:10:10 +0000
committerUlrich Drepper <drepper@redhat.com>2004-12-22 20:10:10 +0000
commita334319f6530564d22e775935d9c91663623a1b4 (patch)
treeb5877475619e4c938e98757d518bb1e9cbead751 /sysdeps/mach/hurd/mips
parent0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (diff)
downloadglibc-a334319f6530564d22e775935d9c91663623a1b4.tar
glibc-a334319f6530564d22e775935d9c91663623a1b4.tar.gz
glibc-a334319f6530564d22e775935d9c91663623a1b4.tar.bz2
glibc-a334319f6530564d22e775935d9c91663623a1b4.zip
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
Diffstat (limited to 'sysdeps/mach/hurd/mips')
-rw-r--r--sysdeps/mach/hurd/mips/Dist3
-rw-r--r--sysdeps/mach/hurd/mips/bits/sigcontext.h80
-rw-r--r--sysdeps/mach/hurd/mips/dl-machine.c132
-rw-r--r--sysdeps/mach/hurd/mips/exc2signal.c97
-rw-r--r--sysdeps/mach/hurd/mips/init-fault.c41
-rw-r--r--sysdeps/mach/hurd/mips/init-first.c414
-rw-r--r--sysdeps/mach/hurd/mips/intr-msg.h127
-rw-r--r--sysdeps/mach/hurd/mips/longjmp-ctx.c41
-rw-r--r--sysdeps/mach/hurd/mips/longjmp-ts.c45
-rw-r--r--sysdeps/mach/hurd/mips/sigreturn.c223
-rw-r--r--sysdeps/mach/hurd/mips/trampoline.c292
11 files changed, 1495 insertions, 0 deletions
diff --git a/sysdeps/mach/hurd/mips/Dist b/sysdeps/mach/hurd/mips/Dist
new file mode 100644
index 0000000000..b6f3ffa4c3
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/Dist
@@ -0,0 +1,3 @@
+longjmp-ctx.c
+init-fault.c
+dl-machine.c
diff --git a/sysdeps/mach/hurd/mips/bits/sigcontext.h b/sysdeps/mach/hurd/mips/bits/sigcontext.h
new file mode 100644
index 0000000000..14c618857e
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/bits/sigcontext.h
@@ -0,0 +1,80 @@
+/* Machine-dependent signal context structure for GNU Hurd. MIPS version.
+ Copyright (C) 1994,97,2001 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
+# error "Never use <bits/sigcontext.h> directly; include <signal.h> instead."
+#endif
+
+#ifndef sc_mips_thread_state
+
+/* Signal handlers are actually called:
+ void handler (int sig, int code, struct sigcontext *scp); */
+
+/* State of this thread when the signal was taken. */
+struct sigcontext
+ {
+ /* These first members are machine-independent. */
+
+ int sc_onstack; /* Nonzero if running on sigstack. */
+ __sigset_t sc_mask; /* Blocked signals to restore. */
+
+ /* MiG reply port this thread is using. */
+ unsigned int sc_reply_port;
+
+ /* Port this thread is doing an interruptible RPC on. */
+ unsigned int sc_intr_port;
+
+ /* Error code associated with this signal (interpreted as `error_t'). */
+ int sc_error;
+
+ /* All following members are machine-dependent. The rest of this
+ structure is written to be laid out identically to:
+ {
+ struct mips_thread_state ts;
+ struct mips_exc_state es;
+ struct mips_float_state fs;
+ }
+ trampoline.c knows this, so it must be changed if this changes. */
+#define sc_mips_thread_state sc_gpr /* Beginning of correspondence. */
+ int sc_gpr[31]; /* "General" registers; [0] is r1. */
+ int sc_mdlo, sc_mdhi; /* Low and high multiplication results. */
+ int sc_pc; /* Instruction pointer. */
+
+ /* struct mips_exc_state */
+#define sc_mips_exc_state sc_cause
+ unsigned int sc_cause; /* Machine-level trap code. */
+#define SC_CAUSE_SST 0x00000044
+ unsigned int sc_badvaddr;
+ unsigned int sc_coproc_used; /* Which coprocessors the thread has used. */
+#define SC_COPROC_USE_COP0 1 /* (by definition) */
+#define SC_COPROC_USE_COP1 2 /* FPA */
+#define SC_COPROC_USE_FPU SC_COPROC_USE_COP1
+#define SC_COPROC_USE_COP2 4
+#define SC_COPROC_USE_COP3 8
+
+ /* struct mips_float_state
+ This is only filled in if the SC_COPROC_USE_FPU bit
+ is set in sc_coproc_used. */
+#define sc_mips_float_state sc_fpr
+ int sc_fpr[32]; /* FP registers. */
+ int sc_fpcsr; /* FPU status register. */
+ int sc_fpeir; /* FP exception instruction register. */
+ };
+
+#endif /* sc_mips_thread_state */
diff --git a/sysdeps/mach/hurd/mips/dl-machine.c b/sysdeps/mach/hurd/mips/dl-machine.c
new file mode 100644
index 0000000000..ce2d5db510
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/dl-machine.c
@@ -0,0 +1,132 @@
+/* Operating system support for run-time dynamic linker. MIPS specific
+ stuffs on Hurd.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd.h>
+#include <link.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <sysdep.h>
+#include <mach/mig_support.h>
+#include "../stdio-common/_itoa.h"
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <libintl.h>
+
+void weak_function
+abort (void)
+{
+ _exit (127);
+}
+
+
+#include <string.h>
+#include <mach/error.h>
+#include <errorlib.h>
+
+#undef _
+#define _(x) x
+
+/* Return a string describing the errno code in ERRNUM. */
+char * weak_function
+_strerror_internal (int errnum, char *buf, size_t buflen)
+{
+ int system;
+ int sub;
+ int code;
+ const struct error_system *es;
+ extern void __mach_error_map_compat (int *);
+
+ __mach_error_map_compat (&errnum);
+
+ system = err_get_system (errnum);
+ sub = err_get_sub (errnum);
+ code = err_get_code (errnum);
+
+ if (system > err_max_system || ! __mach_error_systems[system].bad_sub)
+ {
+ const char *unk = _("Error in unknown error system: ");
+ const size_t unklen = strlen (unk);
+ char *p = buf + buflen;
+ *--p = '\0';
+ p = _itoa (errnum, p, 16, 1);
+ return memcpy (p - unklen, unk, unklen);
+ }
+
+ es = &__mach_error_systems[system];
+
+ if (sub >= es->max_sub)
+ return (char *) es->bad_sub;
+
+ if (code >= es->subsystem[sub].max_code)
+ {
+ const char *unk = _("Unknown error ");
+ const size_t unklen = strlen (unk);
+ char *p = buf + buflen;
+ size_t len = strlen (es->subsystem[sub].subsys_name);
+ *--p = '\0';
+ p = _itoa (errnum, p, 16, 1);
+ *p-- = ' ';
+ p = memcpy (p - len, es->subsystem[sub].subsys_name, len);
+ return memcpy (p - unklen, unk, unklen);
+ }
+
+ return (char *) _(es->subsystem[sub].codes[code]);
+}
+
+/* Read the whole contents of FILE into new mmap'd space with given
+ protections. The size of the file is returned in SIZE. */
+void *
+_dl_sysdep_read_whole_file (const char *file, size_t *size, int prot)
+{
+ struct stat stat;
+ mach_port_t memobj_rd;
+ void *contents;
+ error_t err;
+
+ memobj_rd = __open (file, O_RDONLY, 0);
+ if (memobj_rd)
+ {
+ err = __io_stat ((file_t) memobj_rd, &stat);
+ if (err)
+ {
+ __hurd_fail (err);
+ contents = 0;
+ }
+ else
+ {
+ /* Map a copy of the file contents. */
+ contents = __mmap (0, stat.st_size, prot, MAP_COPY, memobj_rd, 0);
+ if (contents == (void *)-1)
+ contents = 0;
+ else
+ *size = stat.st_size;
+ }
+
+ __mach_port_deallocate (__mach_task_self (), memobj_rd);
+ }
+ else
+ contents = 0;
+
+ return contents;
+}
diff --git a/sysdeps/mach/hurd/mips/exc2signal.c b/sysdeps/mach/hurd/mips/exc2signal.c
new file mode 100644
index 0000000000..c505ae5b22
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/exc2signal.c
@@ -0,0 +1,97 @@
+/* Translate Mach exception codes into signal numbers. MIPS version.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <mach/exception.h>
+
+/* Translate the Mach exception codes, as received in an `exception_raise' RPC,
+ into a signal number and signal subcode. */
+
+void
+_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+{
+ detail->error = 0;
+
+ switch (detail->exc)
+ {
+ default:
+ *signo = SIGIOT;
+ detail->code = detail->exc;
+ break;
+
+ case EXC_BAD_ACCESS:
+ if (detail->exc_code == KERN_PROTECTION_FAILURE)
+ *signo = SIGSEGV;
+ else
+ *signo = SIGBUS;
+ detail->code = detail->exc_subcode;
+ detail->error = detail->exc_code;
+ break;
+
+ case EXC_BAD_INSTRUCTION:
+ *signo = SIGILL;
+ if (detail->exc_code == EXC_MIPS_II)
+ detail->code = detail->exc_subcode;
+ else
+ detail->code = 0;
+ break;
+
+ case EXC_ARITHMETIC:
+ switch (detail->exc_code)
+ {
+ case EXC_MIPS_OV: /* integer overflow */
+ *signo = SIGFPE;
+ detail->code = detail->exc_subcode;
+ break;
+
+ default:
+ *signo = SIGFPE;
+ detail->code = 0;
+ break;
+
+ case EXC_MIPS_INT:
+ /* Subcode is the fp_status word saved by the hardware.
+ Give an error code corresponding to the first bit set. */
+ if (detail->exc_subcode == EXC_MIPS_FLT_UNIMP)
+ *signo = SIGILL;
+ else
+ *signo = SIGFPE;
+ detail->code = detail->exc_subcode;
+ break;
+ }
+ break;
+
+ case EXC_EMULATION:
+ /* 3.0 doesn't give this one, why, I don't know. */
+ *signo = SIGEMT;
+ detail->code = 0;
+ break;
+
+ case EXC_SOFTWARE:
+ *signo = SIGEMT;
+ detail->code = 0;
+ break;
+
+ case EXC_BREAKPOINT:
+ *signo = SIGTRAP;
+ detail->code = 0;
+ break;
+ }
+}
diff --git a/sysdeps/mach/hurd/mips/init-fault.c b/sysdeps/mach/hurd/mips/init-fault.c
new file mode 100644
index 0000000000..05f48a3a56
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/init-fault.c
@@ -0,0 +1,41 @@
+/* Set up a thread_state for proc_handle_exceptions. MIPS version.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd/signal.h>
+#include <mach/thread_status.h>
+#include <string.h>
+#include <setjmp.h>
+
+extern jmp_buf _hurd_sigthread_fault_env;
+
+static char fault_stack[32];
+static volatile void
+faulted (void)
+{
+ __longjmp (_hurd_sigthread_fault_env, 1);
+}
+
+void
+_hurd_initialize_fault_recovery_state (void *state)
+{
+ struct mips_thread_state *ts = state;
+ memset (ts, 0, sizeof (*ts));
+ ts->r29 = (int) &fault_stack[sizeof (fault_stack)];
+ ts->pc = (int) &faulted;
+}
diff --git a/sysdeps/mach/hurd/mips/init-first.c b/sysdeps/mach/hurd/mips/init-first.c
new file mode 100644
index 0000000000..6f53e839b3
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/init-first.c
@@ -0,0 +1,414 @@
+/* Initialization code run first thing by the ELF startup code. For Mips/Hurd.
+ Copyright (C) 1996,1997,1998,2000,01,02,03 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "hurdstartup.h"
+#include "set-hooks.h"
+#include "hurdmalloc.h" /* XXX */
+
+extern void __mach_init (void);
+extern void __init_misc (int, char **, char **);
+#ifdef USE_NONOPTION_FLAGS
+extern void __getopt_clean_environment (char **);
+#endif
+#ifndef SHARED
+extern void _dl_non_dynamic_init (void) internal_function;
+#endif
+extern void __libc_global_ctors (void);
+
+unsigned int __hurd_threadvar_max;
+unsigned long int __hurd_threadvar_stack_offset;
+unsigned long int __hurd_threadvar_stack_mask;
+
+int __libc_multiple_libcs attribute_hidden = 1;
+
+int __libc_argc attribute_hidden;
+char **__libc_argv attribute_hidden;
+
+void *(*_cthread_init_routine) (void); /* Returns new SP to use. */
+void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
+
+
+/* Things that want to be run before _hurd_init or much anything else.
+ Importantly, these are called before anything tries to use malloc. */
+DEFINE_HOOK (_hurd_preinit_hook, (void));
+
+static void
+init1 (int argc, char *arg0, ...)
+{
+ char **argv = &arg0;
+ char **envp = &argv[argc + 1];
+ struct hurd_startup_data *d;
+
+ __libc_argc = argc;
+ __libc_argv = argv;
+ __environ = envp;
+ while (*envp)
+ ++envp;
+ d = (void *) ++envp;
+
+ /* If we are the bootstrap task started by the kernel,
+ then after the environment pointers there is no Hurd
+ data block; the argument strings start there. */
+ if ((void *) d != argv[0])
+ {
+ _hurd_init_dtable = d->dtable;
+ _hurd_init_dtablesize = d->dtablesize;
+
+ {
+ /* Check if the stack we are now on is different from
+ the one described by _hurd_stack_{base,size}. */
+
+ char dummy;
+ const vm_address_t newsp = (vm_address_t) &dummy;
+
+ if (d->stack_size != 0 && (newsp < d->stack_base ||
+ newsp - d->stack_base > d->stack_size))
+ /* The new stack pointer does not intersect with the
+ stack the exec server set up for us, so free that stack. */
+ __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
+ }
+ }
+
+ if (__hurd_threadvar_stack_mask == 0)
+ {
+ /* We are not using cthreads, so we will have just a single allocated
+ area for the per-thread variables of the main user thread. */
+ unsigned long int i;
+ __hurd_threadvar_stack_offset
+ = (unsigned long int) malloc (__hurd_threadvar_max *
+ sizeof (unsigned long int));
+ if (__hurd_threadvar_stack_offset == 0)
+ __libc_fatal ("Can't allocate single-threaded per-thread variables.");
+ for (i = 0; i < __hurd_threadvar_max; ++i)
+ ((unsigned long int *) __hurd_threadvar_stack_offset)[i] = 0;
+ }
+
+ if ((void *) d != argv[0] && (d->portarray || d->intarray))
+ /* Initialize library data structures, start signal processing, etc. */
+ _hurd_init (d->flags, argv,
+ d->portarray, d->portarraysize,
+ d->intarray, d->intarraysize);
+
+#ifndef SHARED
+ _dl_non_dynamic_init ();
+#endif
+ __init_misc (argc, argv, __environ);
+
+#ifdef USE_NONOPTION_FLAGS
+ /* This is a hack to make the special getopt in GNU libc working. */
+ __getopt_clean_environment (envp);
+#endif
+
+#ifdef SHARED
+ __libc_global_ctors ();
+#endif
+
+ (void) &init1;
+}
+
+static void *
+__init (int *data)
+{
+ int argc = *data;
+ char **argv = (void *) (data + 1);
+ char **envp = &argv[argc + 1];
+ struct hurd_startup_data *d;
+
+ __environ = envp;
+ while (*envp)
+ ++envp;
+ d = (void *) ++envp;
+
+ /* The user might have defined a value for this, to get more variables.
+ Otherwise it will be zero on startup. We must make sure it is set
+ properly before before cthreads initialization, so cthreads can know
+ how much space to leave for thread variables. */
+ if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
+ __hurd_threadvar_max = _HURD_THREADVAR_MAX;
+
+
+ /* After possibly switching stacks, call `init1' (above) with the user
+ code as the return address, and the argument data immediately above
+ that on the stack. */
+
+ if (_cthread_init_routine)
+ {
+ /* Initialize cthreads, which will allocate us a new stack to run on. */
+ void *newsp = (*_cthread_init_routine) ();
+ struct hurd_startup_data *od;
+
+ /* Copy the argdata from the old stack to the new one. */
+ newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
+ (char *) d - (char *) data);
+
+ /* Set up the Hurd startup data block immediately following
+ the argument and environment pointers on the new stack. */
+ od = (newsp + ((char *) d - (char *) data));
+ if ((void *) argv[0] == d)
+ /* We were started up by the kernel with arguments on the stack.
+ There is no Hurd startup data, so zero the block. */
+ memset (od, 0, sizeof *od);
+ else
+ /* Copy the Hurd startup data block to the new stack. */
+ *od = *d;
+
+ /* Push the user code address on the top of the new stack. It will
+ be the return address for `init1'; we will jump there with NEWSP
+ as the stack pointer. */
+ return newsp;
+ }
+
+ /* The argument data is just above the stack frame we will unwind by
+ returning. */
+ return (void *) data;
+
+ (void) &__init;
+}
+
+#ifdef SHARED
+/* This function is called to initialize the shared C library.
+ It is called just before the user _start code from mips/elf/start.S,
+ with the stack set up as that code gets it. */
+
+/* NOTE! The linker notices the magical name `_init' and sets the DT_INIT
+ pointer in the dynamic section based solely on that. It is convention
+ for this function to be in the `.init' section, but the symbol name is
+ the only thing that really matters!! */
+/*void _init (int argc, ...) __attribute__ ((unused, section (".init")));*/
+
+#if __mips64
+asm ("\
+ .section .init,\"ax\",@progbits\n\
+ .align 3\n\
+ .globl _init\n\
+ .type _init,@function\n\
+ .ent _init\n\
+_init:\n\
+ .set noreorder\n\
+ .cpload $25\n\
+ .set reorder\n\
+ dsubu $29, 8*8\n\
+ .cprestore 6*8\n\
+ sd $16, 4*8($29)\n\
+ sd $31, 5*8($29)\n\
+ jal preinit\n\
+ sd $28, 6*8($29)\n\
+ move $16, $29 # Save the old stack pointer to s0 ($16)\n\
+ daddu $4, $29, 4*8\n\
+ jal __init\n\
+ # Restore saved registers from the old stack.\n\
+ ld $28, 6*8($16)\n\
+ ld $31, 5*8($16)\n\
+ ld $16, 4*8($16)\n\
+ move $29, $2 # set new sp to SP\n\
+call_init1:\n\
+ ld $4, 0($29)\n\
+ ld $5, 1*8($29)\n\
+ ld $6, 2*8($29)\n\
+ ld $7, 3*8($29)\n\
+ dla $25, init1\n\
+ jr $25\n\
+ .end _init\n\
+ .text\n\
+");
+#else
+asm ("\
+ .section .init,\"ax\",@progbits\n\
+ .align 2\n\
+ .globl _init\n\
+ .type _init,@function\n\
+ .ent _init\n\
+_init:\n\
+ .set noreorder\n\
+ .cpload $25\n\
+ .set reorder\n\
+ subu $29, 32\n\
+ .cprestore 24\n\
+ sw $16, 16($29)\n\
+ sw $31, 20($29)\n\
+ jal preinit\n\
+ sw $28, 24($29)\n\
+ move $16, $29 # Save the old stack pointer to s0 ($16)\n\
+ addu $4, $29, 32\n\
+ jal __init\n\
+ # Restore saved registers from the old stack.\n\
+ lw $28, 24($16)\n\
+ lw $31, 20($16)\n\
+ lw $16, 16($16)\n\
+ move $29, $2 # set new sp to SP\n\
+call_init1:\n\
+ lw $4, 0($29)\n\
+ lw $5, 4($29)\n\
+ lw $6, 8($29)\n\
+ lw $7, 12($29)\n\
+ la $25, init1\n\
+ jr $25\n\
+ .end _init\n\
+ .text\n\
+");
+#endif
+
+static void
+preinit (void)
+{
+ /* Initialize data structures so we can do RPCs. */
+ __mach_init ();
+
+ RUN_HOOK (_hurd_preinit_hook, ());
+
+ (void) &preinit;
+}
+
+void __libc_init_first (int argc, ...)
+{
+}
+#endif
+
+#ifndef SHARED
+/* An assembler code wrapping c function __init. */
+#ifdef __mips64
+asm ("\
+ .text\n\
+ .align 3\n\
+init:\n\
+ dsubu $29, 8*8\n\
+ sd $16, 4*8($29)\n\
+ sd $31, 5*8($29)\n\
+ move $16, $29\n\
+ jal __init\n\
+ ld $31, 5*8($16)\n\
+ ld $16, 4*8($16)\n\
+ move $29, $2 # set new sp to SP\n\
+call_init1:\n\
+ ld $4, 0($29)\n\
+ ld $5, 1*8($29)\n\
+ ld $6, 2*8($29)\n\
+ ld $7, 3*8($29)\n\
+ dla $25, init1\n\
+ jr $25\n\
+");
+#else
+asm ("\
+ .text\n\
+ .align 2\n\
+init:\n\
+ subu $29, 32\n\
+ sw $16, 16($29)\n\
+ sw $31, 20($29)\n\
+ move $16, $29\n\
+ jal __init\n\
+ lw $31, 20($16)\n\
+ lw $16, 16($16)\n\
+ move $29, $2 # set new sp to SP\n\
+call_init1:\n\
+ lw $4, 0($29)\n\
+ lw $5, 4($29)\n\
+ lw $6, 8($29)\n\
+ lw $7, 12($29)\n\
+ la $25, init1\n\
+ jr $25\n\
+");
+#endif
+
+/* An assembler code wrapping c function ___libc_init_first.
+ ___libc_init_first does an RPC call to flush cache to put doinit
+ function on the stack, so we should call __mach_init first in
+ this wrap. */
+#ifdef __mips64
+asm ("\
+ .text\n\
+ .align 3\n\
+ .globl __libc_init_first\n\
+__libc_init_first:\n\
+ dsubu $29, 8\n\
+ sd $31, 0($29)\n\
+ jal __mach_init\n\
+ ld $4, 0($29)\n\
+ ld $5, 1*8($29)\n\
+ ld $6, 2*8($29)\n\
+ ld $7, 3*8($29)\n\
+ j ___libc_init_first\n\
+");
+#else
+asm ("\
+ .text\n\
+ .align 2\n\
+ .globl __libc_init_first\n\
+__libc_init_first:\n\
+ subu $29, 4\n\
+ sw $31, 0($29)\n\
+ jal __mach_init\n\
+ lw $4, 0($29)\n\
+ lw $5, 4($29)\n\
+ lw $6, 8($29)\n\
+ lw $7, 12($29)\n\
+ j ___libc_init_first\n\
+");
+#endif
+
+static void
+___libc_init_first (int return_addr, int argc, ...)
+{
+ void doinit (int *data)
+ {
+#if 0
+ /* This function gets called with the argument data at TOS. */
+ void doinit1 (int argc, ...)
+ {
+ init (&argc);
+ }
+#endif
+ extern void init (int *data);
+
+ /* Push the user return address after the argument data, and then
+ jump to `doinit1' (above), so it is as if __libc_init_first's
+ caller had called `init' with the argument data already on the
+ stack. */
+ *--data = return_addr;
+
+#ifdef __mips64
+ asm volatile ("ld $31, 0(%0)\n" /* Load the original return address. */
+ "daddu $29, %0, 8\n" /* Switch to new outermost stack. */
+ "move $4, $29\n"
+ "jr %1" : : "r" (data), "r" (&init));
+#else
+ asm volatile ("lw $31, 0(%0)\n" /* Load the original return address. */
+ "addu $29, %0, 4\n" /* Switch to new outermost stack. */
+ "move $4, $29\n"
+ "jr %1" : : "r" (data), "r" (&init));
+#endif
+ /* NOTREACHED */
+ }
+
+#if 0
+ /* Initialize data structures so we can do RPCs. */
+ __mach_init ();
+#endif
+
+ RUN_HOOK (_hurd_preinit_hook, ());
+
+ _hurd_startup ((void **) &argc, &doinit);
+
+ (void) &___libc_init_first;
+}
+#endif
diff --git a/sysdeps/mach/hurd/mips/intr-msg.h b/sysdeps/mach/hurd/mips/intr-msg.h
new file mode 100644
index 0000000000..16c78972ac
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/intr-msg.h
@@ -0,0 +1,127 @@
+/* Machine-dependent details of interruptible RPC messaging. Mips version.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+
+#ifdef __mips64
+#define INTR_MSG_TRAP(msg, option, send_size, rcv_size, rcv_name, timeout, notify) \
+({ \
+ error_t err; \
+ mach_port_t __rcv_name = (rcv_name); \
+ mach_msg_timeout_t __timeout = (timeout); \
+ mach_port_t __notify = (notify); \
+ asm (".globl _hurd_intr_rpc_msg_do_trap\n" \
+ ".globl _hurd_intr_rpc_msg_in_trap\n" \
+ " move $4, %1\n" \
+ " move $5, %2\n" \
+ " move $6, %3\n" \
+ " move $7, %4\n" \
+ " move $8, %5\n" \
+ " move $9, %6\n" \
+ " move $10, %7\n" \
+ " dli $2, -25\n" \
+ "_hurd_intr_rpc_msg_do_trap: syscall\n" \
+ "_hurd_intr_rpc_msg_in_trap: move %0, $2\n" \
+ : "=r" (err) \
+ : "r" (msg), "r" (option), "r" (send_size), "r" (rcv_size), \
+ "r" (__rcv_name), "r" (__timeout), "r" (__notify) \
+ : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", \
+ "$11", "$12", "$13", "$14", "$15", "$24", "$25", "$28"); \
+ err; \
+})
+#else
+#define INTR_MSG_TRAP(msg, option, send_size, rcv_size, rcv_name, timeout, notify) \
+({ \
+ error_t err; \
+ mach_port_t __rcv_name = (rcv_name); \
+ mach_msg_timeout_t __timeout = (timeout); \
+ mach_port_t __notify = (notify); \
+ asm (".globl _hurd_intr_rpc_msg_do_trap\n" \
+ ".globl _hurd_intr_rpc_msg_in_trap\n" \
+ " move $4, %1\n" \
+ " move $5, %2\n" \
+ " move $6, %3\n" \
+ " move $7, %4\n" \
+ " move $8, %5\n" \
+ " move $9, %6\n" \
+ " move $10, %7\n" \
+ " li $2, -25\n" \
+ "_hurd_intr_rpc_msg_do_trap: syscall\n" \
+ "_hurd_intr_rpc_msg_in_trap: move %0, $2\n" \
+ : "=r" (err) \
+ : "r" (msg), "r" (option), "r" (send_size), "r" (rcv_size), \
+ "r" (__rcv_name), "r" (__timeout), "r" (__notify) \
+ : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", \
+ "$11", "$12", "$13", "$14", "$15", "$24", "$25", "$28"); \
+ err; \
+})
+#endif
+
+static inline void
+INTR_MSG_BACK_OUT (struct mips_thread_state *state)
+{
+ return;
+}
+
+#include "hurdfault.h"
+
+static inline int
+SYSCALL_EXAMINE (struct mips_thread_state *state, int *callno)
+{
+ u_int32_t *p = (void *) (state->pc - 4);
+ int result;
+ if (_hurdsig_catch_memory_fault (p))
+ return 0;
+ if (result = (*p == 0x0000000c))
+ /* The PC is just after a `syscall' instruction.
+ This is a system call in progress; v0($2) holds the call number. */
+ *callno = state->r2;
+ _hurdsig_end_catch_fault ();
+ return result;
+}
+
+
+struct mach_msg_trap_args
+ {
+ /* This is the order of arguments to mach_msg_trap. */
+ mach_msg_header_t *msg;
+ mach_msg_option_t option;
+ mach_msg_size_t send_size;
+ mach_msg_size_t rcv_size;
+ mach_port_t rcv_name;
+ mach_msg_timeout_t timeout;
+ mach_port_t notify;
+ };
+
+
+static inline mach_port_t
+MSG_EXAMINE (struct mips_thread_state *state, int *msgid)
+{
+ mach_msg_header_t *msg;
+ mach_port_t send_port;
+
+ msg = (mach_msg_header_t *) state->r4;
+
+ if (_hurdsig_catch_memory_fault (msg))
+ return MACH_PORT_NULL;
+ send_port = msg->msgh_remote_port;
+ *msgid = msg->msgh_id;
+ _hurdsig_end_catch_fault ();
+
+ return send_port;
+}
diff --git a/sysdeps/mach/hurd/mips/longjmp-ctx.c b/sysdeps/mach/hurd/mips/longjmp-ctx.c
new file mode 100644
index 0000000000..66ee7b6fb8
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/longjmp-ctx.c
@@ -0,0 +1,41 @@
+/* Perform a `longjmp' on a `struct sigcontext'. MIPS version.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <setjmp.h>
+#include <hurd/signal.h>
+#include <string.h>
+
+void
+_hurd_longjmp_sigcontext (struct sigcontext *scp, jmp_buf env, int retval)
+{
+ scp->sc_gpr[16] = env[0].__regs[0];
+ scp->sc_gpr[17] = env[0].__regs[1];
+ scp->sc_gpr[18] = env[0].__regs[2];
+ scp->sc_gpr[19] = env[0].__regs[3];
+ scp->sc_gpr[20] = env[0].__regs[4];
+ scp->sc_gpr[21] = env[0].__regs[5];
+ scp->sc_gpr[22] = env[0].__regs[6];
+ scp->sc_gpr[23] = env[0].__regs[7];
+
+ scp->sc_gpr[28] = (int) env[0].__gp;
+ scp->sc_fp = (int) env[0].__fp;
+ scp->sc_sp = (int) env[0].__sp;
+ scp->sc_pc = (int) env[0].__pc;
+ scp->sc_gpr[2] = retval ?: 1;
+}
diff --git a/sysdeps/mach/hurd/mips/longjmp-ts.c b/sysdeps/mach/hurd/mips/longjmp-ts.c
new file mode 100644
index 0000000000..4c69e4e2b9
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/longjmp-ts.c
@@ -0,0 +1,45 @@
+/* Perform a `longjmp' on a Mach thread_state. MIPS version.
+ Copyright (C) 1996, 1997 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd/signal.h>
+#include <setjmp.h>
+#include <mach/thread_status.h>
+
+
+/* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'. */
+
+void
+_hurd_longjmp_thread_state (void *state, jmp_buf env, int val)
+{
+ struct mips_thread_state *ts = state;
+
+ ts->r16 = env[0].__jmpbuf[0].__regs[0];
+ ts->r17 = env[0].__jmpbuf[0].__regs[1];
+ ts->r18 = env[0].__jmpbuf[0].__regs[2];
+ ts->r19 = env[0].__jmpbuf[0].__regs[3];
+ ts->r20 = env[0].__jmpbuf[0].__regs[4];
+ ts->r21 = env[0].__jmpbuf[0].__regs[5];
+ ts->r22 = env[0].__jmpbuf[0].__regs[6];
+ ts->r23 = env[0].__jmpbuf[0].__regs[7];
+ ts->r28 = (int) env[0].__jmpbuf[0].__gp;
+ ts->r29 = (int) env[0].__jmpbuf[0].__sp;
+ ts->r30 = (int) env[0].__jmpbuf[0].__fp;
+ ts->pc = (int) env[0].__jmpbuf[0].__pc;
+ ts->r2 = val ?: 1;
+}
diff --git a/sysdeps/mach/hurd/mips/sigreturn.c b/sysdeps/mach/hurd/mips/sigreturn.c
new file mode 100644
index 0000000000..a9f7673eb5
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/sigreturn.c
@@ -0,0 +1,223 @@
+/* Copyright (C) 1996, 1997, 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <hurd/threadvar.h>
+#include <stdlib.h>
+#include <mach/mips/mips_instruction.h>
+
+int
+__sigreturn (struct sigcontext *scp)
+{
+ struct hurd_sigstate *ss;
+ struct hurd_userlink *link = (void *) &scp[1];
+ mach_port_t *reply_port;
+
+ if (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ss = _hurd_self_sigstate ();
+ __spin_lock (&ss->lock);
+
+ /* Remove the link on the `active resources' chain added by
+ _hurd_setup_sighandler. Its purpose was to make sure
+ that we got called; now we have, it is done. */
+ _hurd_userlink_unlink (link);
+
+ /* Restore the set of blocked signals, and the intr_port slot. */
+ ss->blocked = scp->sc_mask;
+ ss->intr_port = scp->sc_intr_port;
+
+ /* Check for pending signals that were blocked by the old set. */
+ if (ss->pending & ~ss->blocked)
+ {
+ /* There are pending signals that just became unblocked. Wake up the
+ signal thread to deliver them. But first, squirrel away SCP where
+ the signal thread will notice it if it runs another handler, and
+ arrange to have us called over again in the new reality. */
+ ss->context = scp;
+ __spin_unlock (&ss->lock);
+ __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
+ /* If a pending signal was handled, sig_post never returned. */
+ __spin_lock (&ss->lock);
+ ss->context = NULL;
+ }
+
+ if (scp->sc_onstack)
+ {
+ ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
+ /* XXX cannot unlock until off sigstack */
+ abort ();
+ }
+ else
+ __spin_unlock (&ss->lock);
+
+ /* Destroy the MiG reply port used by the signal handler, and restore the
+ reply port in use by the thread when interrupted. */
+ reply_port =
+ (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+ if (*reply_port)
+ {
+ mach_port_t port = *reply_port;
+
+ /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port not to
+ get another reply port, but avoids mig_dealloc_reply_port trying to
+ deallocate it after the receive fails (which it will, because the
+ reply port will be bogus, whether we do this or not). */
+ *reply_port = MACH_PORT_DEAD;
+
+ __mach_port_destroy (__mach_task_self (), port);
+ }
+ *reply_port = scp->sc_reply_port;
+
+ if (scp->sc_coproc_used & SC_COPROC_USE_FPU)
+ {
+ /* Restore FPU state. */
+#define restore_fpr(n) \
+ asm volatile ("l.d $f" #n ",%0" : : "m" (scp->sc_fpr[n]))
+
+ /* Restore floating-point registers. */
+#ifdef __mips64
+ restore_fpr (0);
+ restore_fpr (1);
+ restore_fpr (2);
+ restore_fpr (3);
+ restore_fpr (4);
+ restore_fpr (5);
+ restore_fpr (6);
+ restore_fpr (7);
+ restore_fpr (8);
+ restore_fpr (9);
+ restore_fpr (10);
+ restore_fpr (11);
+ restore_fpr (12);
+ restore_fpr (13);
+ restore_fpr (14);
+ restore_fpr (15);
+ restore_fpr (16);
+ restore_fpr (17);
+ restore_fpr (18);
+ restore_fpr (19);
+ restore_fpr (20);
+ restore_fpr (21);
+ restore_fpr (22);
+ restore_fpr (23);
+ restore_fpr (24);
+ restore_fpr (25);
+ restore_fpr (26);
+ restore_fpr (27);
+ restore_fpr (28);
+ restore_fpr (29);
+ restore_fpr (30);
+ restore_fpr (31);
+#else
+ restore_fpr (0);
+ restore_fpr (2);
+ restore_fpr (4);
+ restore_fpr (6);
+ restore_fpr (8);
+ restore_fpr (10);
+ restore_fpr (12);
+ restore_fpr (14);
+ restore_fpr (16);
+ restore_fpr (18);
+ restore_fpr (20);
+ restore_fpr (22);
+ restore_fpr (24);
+ restore_fpr (26);
+ restore_fpr (28);
+ restore_fpr (30);
+#endif
+
+ /* Restore the floating-point control/status register ($f31). */
+ asm volatile ("ctc1 %0,$f31" : : "r" (scp->sc_fpcsr));
+ }
+
+ /* Load all the registers from the sigcontext. */
+#ifdef __mips64
+#define restore_gpr(n) \
+ asm volatile ("ld $" #n ",%0" : : "m" (scpreg->sc_gpr[n - 1]))
+#else
+#define restore_gpr(n) \
+ asm volatile ("lw $" #n ",%0" : : "m" (scpreg->sc_gpr[n - 1]))
+#endif
+
+ {
+ register const struct sigcontext *const scpreg asm ("$1") = scp;
+ register int *at asm ("$1");
+
+ /* First restore the multiplication result registers. The compiler
+ will use some temporary registers, so we do this before restoring
+ the general registers. */
+ asm volatile ("mtlo %0" : : "r" (scpreg->sc_mdlo));
+ asm volatile ("mthi %0" : : "r" (scpreg->sc_mdhi));
+
+ /* In the word after the saved PC, store the saved $1 value. */
+ (&scpreg->sc_pc)[1] = scpreg->sc_gpr[0];
+
+ asm volatile (".set noreorder; .set noat;");
+
+ /* Restore the normal registers. */
+ restore_gpr (2);
+ restore_gpr (3);
+ restore_gpr (4);
+ restore_gpr (5);
+ restore_gpr (6);
+ restore_gpr (7);
+ restore_gpr (8);
+ restore_gpr (9);
+ restore_gpr (10);
+ restore_gpr (11);
+ restore_gpr (12);
+ restore_gpr (13);
+ restore_gpr (14);
+ restore_gpr (15);
+ restore_gpr (16);
+ restore_gpr (17);
+ restore_gpr (18);
+ restore_gpr (19);
+ restore_gpr (20);
+ restore_gpr (21);
+ restore_gpr (22);
+ restore_gpr (23);
+ restore_gpr (24);
+ restore_gpr (25);
+ /* Registers 26-27 are kernel-only. */
+ restore_gpr (28);
+ restore_gpr (29); /* Stack pointer. */
+ restore_gpr (30); /* Frame pointer. */
+ restore_gpr (31); /* Return address. */
+
+ at = &scpreg->sc_pc;
+ /* This is an emulated instruction that will find at the address in $1
+ two words: the PC value to restore, and the $1 value to restore. */
+ asm volatile (".word %0" : : "i" (op_sigreturn));
+ asm volatile (".set reorder; .set at;");
+ /* NOTREACHED */
+ return at; /* To prevent optimization. */
+ }
+
+ /* NOTREACHED */
+ return -1;
+}
+
+weak_alias (__sigreturn, sigreturn)
diff --git a/sysdeps/mach/hurd/mips/trampoline.c b/sysdeps/mach/hurd/mips/trampoline.c
new file mode 100644
index 0000000000..dd42dfc1c6
--- /dev/null
+++ b/sysdeps/mach/hurd/mips/trampoline.c
@@ -0,0 +1,292 @@
+/* Set thread_state for sighandler, and sigcontext to recover. MIPS version.
+ Copyright (C) 1996, 1997, 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd/signal.h>
+#include <hurd/userlink.h>
+#include "thread_state.h"
+#include <assert.h>
+#include <errno.h>
+#include "hurdfault.h"
+#include "intr-msg.h"
+
+
+struct sigcontext *
+_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ int signo, struct hurd_signal_detail *detail,
+ volatile int rpc_wait,
+ struct machine_thread_all_state *state)
+{
+ __label__ trampoline, rpc_wait_trampoline, firewall;
+ void *volatile sigsp;
+ struct sigcontext *scp;
+ struct
+ {
+ int signo;
+ long int sigcode;
+ struct sigcontext *scp; /* Points to ctx, below. */
+ void *sigreturn_addr;
+ void *sigreturn_returns_here;
+ struct sigcontext *return_scp; /* Same; arg to sigreturn. */
+ struct sigcontext ctx;
+ struct hurd_userlink link;
+ } *stackframe;
+
+ if (ss->context)
+ {
+ /* We have a previous sigcontext that sigreturn was about
+ to restore when another signal arrived. We will just base
+ our setup on that. */
+ if (! _hurdsig_catch_memory_fault (ss->context))
+ {
+ memcpy (&state->basic, &ss->context->sc_mips_thread_state,
+ sizeof (state->basic));
+ memcpy (&state->exc, &ss->context->sc_mips_exc_state,
+ sizeof (state->exc));
+ state->set = (1 << MIPS_THREAD_STATE) | (1 << MIPS_EXC_STATE);
+ if (state->exc.coproc_state & SC_COPROC_USE_FPU)
+ {
+ memcpy (&state->fpu, &ss->context->sc_mips_float_state,
+ sizeof (state->fpu));
+ state->set |= (1 << MIPS_FLOAT_STATE);
+ }
+ }
+ }
+
+ if (! machine_get_basic_state (ss->thread, state))
+ return NULL;
+
+ /* Save the original SP in the gratuitous s0 ($16) slot.
+ We may need to reset the SP (the `r29' slot) to avoid clobbering an
+ interrupted RPC frame. */
+ state->basic.r16 = state->basic.r29;
+
+ if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
+ !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
+ {
+ sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
+ ss->sigaltstack.ss_flags |= SS_ONSTACK;
+ /* XXX need to set up base of new stack for
+ per-thread variables, cthreads. */
+ }
+ else
+ sigsp = (char *) state->basic.r29;
+
+ /* Push the arguments to call `trampoline' on the stack. */
+ sigsp -= sizeof (*stackframe);
+ stackframe = sigsp;
+
+ if (_hurdsig_catch_memory_fault (stackframe))
+ {
+ /* We got a fault trying to write the stack frame.
+ We cannot set up the signal handler.
+ Returning NULL tells our caller, who will nuke us with a SIGILL. */
+ return NULL;
+ }
+ else
+ {
+ int ok;
+
+ extern void _hurdsig_longjmp_from_handler (void *, jmp_buf, int);
+
+ /* Add a link to the thread's active-resources list. We mark this as
+ the only user of the "resource", so the cleanup function will be
+ called by any longjmp which is unwinding past the signal frame.
+ The cleanup function (in sigunwind.c) will make sure that all the
+ appropriate cleanups done by sigreturn are taken care of. */
+ stackframe->link.cleanup = &_hurdsig_longjmp_from_handler;
+ stackframe->link.cleanup_data = &stackframe->ctx;
+ stackframe->link.resource.next = NULL;
+ stackframe->link.resource.prevp = NULL;
+ stackframe->link.thread.next = ss->active_resources;
+ stackframe->link.thread.prevp = &ss->active_resources;
+ if (stackframe->link.thread.next)
+ stackframe->link.thread.next->thread.prevp
+ = &stackframe->link.thread.next;
+ ss->active_resources = &stackframe->link;
+
+ /* Set up the arguments for the signal handler. */
+ stackframe->signo = signo;
+ stackframe->sigcode = detail->code;
+ stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
+ stackframe->sigreturn_addr = &__sigreturn;
+ stackframe->sigreturn_returns_here = &&firewall; /* Crash on return. */
+
+ /* Set up the sigcontext from the current state of the thread. */
+
+ scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
+
+ /* struct sigcontext is laid out so that starting at sc_gpr
+ mimics a struct mips_thread_state. */
+ memcpy (&scp->sc_mips_thread_state,
+ &state->basic, sizeof (state->basic));
+
+ /* struct sigcontext is laid out so that starting at sc_cause
+ mimics a struct mips_exc_state. */
+ ok = machine_get_state (ss->thread, state, MIPS_EXC_STATE,
+ &state->exc, &scp->sc_cause,
+ sizeof (state->exc));
+
+ if (ok && (scp->sc_coproc_used & SC_COPROC_USE_FPU))
+ /* struct sigcontext is laid out so that starting at sc_fpr
+ mimics a struct mips_float_state. This state
+ is only meaningful if the coprocessor was used. */
+ ok = machine_get_state (ss->thread, state, MIPS_FLOAT_STATE,
+ &state->fpu, &scp->sc_mips_float_state,
+ sizeof (state->fpu));
+
+ _hurdsig_end_catch_fault ();
+
+ if (! ok)
+ return NULL;
+ }
+
+ /* Modify the thread state to call the trampoline code on the new stack. */
+ if (rpc_wait)
+ {
+ /* The signalee thread was blocked in a mach_msg_trap system call,
+ still waiting for a reply. We will have it run the special
+ trampoline code which retries the message receive before running
+ the signal handler.
+
+ To do this we change the OPTION argument in its registers to
+ enable only message reception, since the request message has
+ already been sent. */
+
+ /* The system call arguments are stored in consecutive registers
+ starting with a0 ($4). */
+ struct mach_msg_trap_args *args = (void *) &state->basic.r4;
+
+ if (_hurdsig_catch_memory_fault (args))
+ {
+ /* Faulted accessing ARGS. Bomb. */
+ return NULL;
+ }
+
+ assert (args->option & MACH_RCV_MSG);
+ /* Disable the message-send, since it has already completed. The
+ calls we retry need only wait to receive the reply message. */
+ args->option &= ~MACH_SEND_MSG;
+
+ /* Limit the time to receive the reply message, in case the server
+ claimed that `interrupt_operation' succeeded but in fact the RPC
+ is hung. */
+ args->option |= MACH_RCV_TIMEOUT;
+ args->timeout = _hurd_interrupted_rpc_timeout;
+
+ _hurdsig_end_catch_fault ();
+
+ state->basic.pc = (int) &&rpc_wait_trampoline;
+ /* The reply-receiving trampoline code runs initially on the original
+ user stack. We pass it the signal stack pointer in s4 ($20). */
+ state->basic.r29 = state->basic.r16; /* Restore mach_msg syscall SP. */
+ state->basic.r20 = (int) sigsp;
+ /* After doing the message receive, the trampoline code will need to
+ update the v0 ($2) value to be restored by sigreturn. To simplify
+ the assembly code, we pass the address of its slot in SCP to the
+ trampoline code in s5 ($21). */
+ state->basic.r21 = (int) &scp->sc_gpr[1];
+ /* We must preserve the mach_msg_trap args in a0..t2 ($4..$10).
+ Pass the handler args to the trampoline code in s1..s3 ($17..$19). */
+ state->basic.r17 = signo;
+ state->basic.r18 = detail->code;
+ state->basic.r19 = (int) scp;
+ }
+ else
+ {
+ state->basic.pc = (int) &&trampoline;
+ state->basic.r29 = (int) sigsp;
+ state->basic.r4 = signo;
+ state->basic.r5 = detail->code;
+ state->basic.r6 = (int) scp;
+ }
+
+ /* We pass the handler function to the trampoline code in s6 ($22). */
+ state->basic.r22 = (int) handler;
+ /* In the callee-saved register s0 ($16), we save the SCP value to pass
+ to __sigreturn after the handler returns. */
+ state->basic.r16 = (int) scp;
+
+ return scp;
+
+ /* The trampoline code follows. This is not actually executed as part of
+ this function, it is just convenient to write it that way. */
+
+ rpc_wait_trampoline:
+ /* This is the entry point when we have an RPC reply message to receive
+ before running the handler. The MACH_MSG_SEND bit has already been
+ cleared in the OPTION argument in our registers. For our convenience,
+ $3 points to the sc_gpr[1] member of the sigcontext (saved v0 ($2)). */
+ asm volatile
+ (".set noat; .set noreorder; .set nomacro\n"
+ /* Retry the interrupted mach_msg system call. */
+#ifdef __mips64
+ "dli $2, -25\n" /* mach_msg_trap */
+#else
+ "li $2, -25\n" /* mach_msg_trap */
+#endif
+ "syscall\n"
+ /* When the sigcontext was saved, v0 was MACH_RCV_INTERRUPTED. But
+ now the message receive has completed and the original caller of
+ the RPC (i.e. the code running when the signal arrived) needs to
+ see the final return value of the message receive in v0. So
+ store the new v0 value into the sc_gpr[1] member of the sigcontext
+ (whose address is in s5 to make this code simpler). */
+#ifdef __mips64
+ "sd $2, ($21)\n"
+#else
+ "sw $2, ($21)\n"
+#endif
+ /* Since the argument registers needed to have the mach_msg_trap
+ arguments, we've stored the arguments to the handler function
+ in registers s1..s3 ($17..$19). */
+ "move $4, $17\n"
+ "move $5, $18\n"
+ "move $6, $19\n"
+ /* Switch to the signal stack. */
+ "move $29, $20\n");
+
+ trampoline:
+ /* Entry point for running the handler normally. The arguments to the
+ handler function are already in the standard registers:
+
+ a0 SIGNO
+ a1 SIGCODE
+ a2 SCP
+ */
+ asm volatile
+ ("move $25, $22\n" /* Copy s6 to t9 for MIPS ABI. */
+ "jal $25; nop\n" /* Call the handler function. */
+ /* Call __sigreturn (SCP); this cannot return. */
+#ifdef __mips64
+ "dla $1,%0\n"
+#else
+ "la $1,%0\n"
+#endif
+ "j $1\n"
+ "move $4, $16" /* Set up arg from saved SCP in delay slot. */
+ : : "i" (&__sigreturn));
+
+ /* NOTREACHED */
+ asm volatile (".set reorder; .set at; .set macro");
+
+ firewall:
+ asm volatile ("hlt: j hlt");
+
+ return NULL;
+}