diff options
Diffstat (limited to 'REORG.TODO/sysdeps/mach/hurd/i386')
18 files changed, 1917 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/Makefile b/REORG.TODO/sysdeps/mach/hurd/i386/Makefile new file mode 100644 index 0000000000..5f988097c2 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/Makefile @@ -0,0 +1,8 @@ +ifeq ($(subdir),misc) +sysdep_routines += ioperm +sysdep_headers += sys/io.h +endif + +ifeq ($(subdir),debug) +gen-as-const-headers += signal-defines.sym +endif diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/Versions b/REORG.TODO/sysdeps/mach/hurd/i386/Versions new file mode 100644 index 0000000000..67e6d94204 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/Versions @@ -0,0 +1,10 @@ +libc { + GLIBC_2.0 { + # Exception handling support functions from libgcc + __register_frame; __register_frame_table; __deregister_frame; + __frame_state_for; __register_frame_info_table; + } + GLIBC_2.2.6 { + ioperm; + } +} diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/____longjmp_chk.S b/REORG.TODO/sysdeps/mach/hurd/i386/____longjmp_chk.S new file mode 100644 index 0000000000..ac28c94e13 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/____longjmp_chk.S @@ -0,0 +1,114 @@ +/* Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include <jmpbuf-offsets.h> +#include <asm-syntax.h> + +#include <signal-defines.h> +/* #include <signal.h> */ +#define SS_ONSTACK 1 + + + .section .rodata.str1.1,"aMS",@progbits,1 + .type longjmp_msg,@object +longjmp_msg: + .string "longjmp causes uninitialized stack frame" + .size longjmp_msg, .-longjmp_msg + + +#ifdef PIC +# define CALL_FAIL movl %ebx, %ecx; /* TODO: what's this mov good for? */ \ + cfi_register(%ebx,%ecx); \ + LOAD_PIC_REG (bx); \ + leal longjmp_msg@GOTOFF(%ebx), %eax; \ + call HIDDEN_JUMPTARGET(__fortify_fail) +#else +# define CALL_FAIL movl $longjmp_msg, %eax; \ + call HIDDEN_JUMPTARGET(__fortify_fail) +#endif + + + .text +ENTRY (____longjmp_chk) + movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ + + /* Save the return address now. */ + movl (JB_PC*4)(%ecx), %edx + /* Get the stack pointer. */ + movl (JB_SP*4)(%ecx), %edi + cfi_undefined(%edi) +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (%edx) + PTR_DEMANGLE (%edi) +#endif + + cmpl %edi, %esp + /* Jumping to a higher-address frame is always allowed. */ + jbe .Lok + + /* Passing here, we're either about to do something invalid, or we're + executing on an alternative signal stack. */ + + /* TODO: need locking? */ + /* struct hurd_sigstate * _hurd_self_sigstate (void) */ +#ifdef PIC + call 1f +1: popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx +#endif + call JUMPTARGET(_hurd_self_sigstate) + /* TODO: %eax and %eax->sigaltstack are always valid? */ + + testl $SS_ONSTACK, (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_FLAGS__OFFSET)(%eax) + /* Fail if SS_ONSTACK is not set. */ + jz .Lfail + + movl (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SP__OFFSET)(%eax), %ebx + addl (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SIZE__OFFSET)(%eax), %ebx + subl %edi, %ebx + cmpl (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SIZE__OFFSET)(%eax), %ebx + /* TODO: comment this calculation. */ + jae .Lok + +.Lfail: CALL_FAIL + +.Lok: /* We add unwind information for the target here. */ + cfi_def_cfa(%ecx, 0) + cfi_register(%eip, %edx) + cfi_register(%esp, %edi) + cfi_offset(%ebx, JB_BX*4) + cfi_offset(%esi, JB_SI*4) + cfi_offset(%edi, JB_DI*4) + cfi_offset(%ebp, JB_BP*4) + + movl 8(%esp), %eax /* Second argument is return value. */ + movl %edi, %esp + + /* Restore registers. */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + cfi_restore(%ebx) + cfi_restore(%esi) + cfi_restore(%edi) + cfi_restore(%ebp) + + /* Jump to saved PC. */ + jmp *%edx +END (____longjmp_chk) diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/bits/sigcontext.h b/REORG.TODO/sysdeps/mach/hurd/i386/bits/sigcontext.h new file mode 100644 index 0000000000..3d5a6736aa --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/bits/sigcontext.h @@ -0,0 +1,121 @@ +/* Machine-dependent signal context structure for GNU Hurd. i386 version. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _BITS_SIGCONTEXT_H +#define _BITS_SIGCONTEXT_H 1 + +#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H +# error "Never use <bits/sigcontext.h> directly; include <signal.h> instead." +#endif + +/* Signal handlers are actually called: + void handler (int sig, int code, struct sigcontext *scp); */ + +#include <bits/types/__sigset_t.h> +#include <mach/machine/fp_reg.h> + +/* 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 i386_thread_state basic; + struct i386_float_state fpu; + } + trampoline.c knows this, so it must be changed if this changes. */ + +#define sc_i386_thread_state sc_gs /* Beginning of correspondence. */ + /* Segment registers. */ + int sc_gs; + int sc_fs; + int sc_es; + int sc_ds; + + /* "General" registers. These members are in the order that the i386 + `pusha' and `popa' instructions use (`popa' ignores %esp). */ + int sc_edi; + int sc_esi; + int sc_ebp; + int sc_esp; /* Not used; sc_uesp is used instead. */ + int sc_ebx; + int sc_edx; + int sc_ecx; + int sc_eax; + + int sc_eip; /* Instruction pointer. */ + int sc_cs; /* Code segment register. */ + + int sc_efl; /* Processor flags. */ + + int sc_uesp; /* This stack pointer is used. */ + int sc_ss; /* Stack segment register. */ + + /* Following mimics struct i386_float_state. Structures and symbolic + values can be found in <mach/i386/fp_reg.h>. */ +#define sc_i386_float_state sc_fpkind + int sc_fpkind; /* FP_NO, FP_387, etc. */ + int sc_fpused; /* If zero, ignore rest of float state. */ + struct i386_fp_save sc_fpsave; + struct i386_fp_regs sc_fpregs; + int sc_fpexcsr; /* FPSR including exception bits. */ + }; + +/* Traditional BSD names for some members. */ +#define sc_sp sc_uesp /* Stack pointer. */ +#define sc_fp sc_ebp /* Frame pointer. */ +#define sc_pc sc_eip /* Process counter. */ +#define sc_ps sc_efl + + +/* Codes for SIGFPE. */ +#define FPE_INTOVF_TRAP 0x1 /* integer overflow */ +#define FPE_INTDIV_FAULT 0x2 /* integer divide by zero */ +#define FPE_FLTOVF_FAULT 0x3 /* floating overflow */ +#define FPE_FLTDIV_FAULT 0x4 /* floating divide by zero */ +#define FPE_FLTUND_FAULT 0x5 /* floating underflow */ +#define FPE_SUBRNG_FAULT 0x7 /* BOUNDS instruction failed */ +#define FPE_FLTDNR_FAULT 0x8 /* denormalized operand */ +#define FPE_FLTINX_FAULT 0x9 /* floating loss of precision */ +#define FPE_EMERR_FAULT 0xa /* mysterious emulation error 33 */ +#define FPE_EMBND_FAULT 0xb /* emulation BOUNDS instruction failed */ + +/* Codes for SIGILL. */ +#define ILL_INVOPR_FAULT 0x1 /* invalid operation */ +#define ILL_STACK_FAULT 0x2 /* fault on microkernel stack access */ +#define ILL_FPEOPR_FAULT 0x3 /* invalid floating operation */ + +/* Codes for SIGTRAP. */ +#define DBG_SINGLE_TRAP 0x1 /* single step */ +#define DBG_BRKPNT_FAULT 0x2 /* breakpoint instruction */ + +#endif /* bits/sigcontext.h */ diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/c++-types.data b/REORG.TODO/sysdeps/mach/hurd/i386/c++-types.data new file mode 100644 index 0000000000..4cde3ca667 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/c++-types.data @@ -0,0 +1,67 @@ +blkcnt64_t:x +blkcnt_t:l +blksize_t:l +caddr_t:Pc +clockid_t:i +clock_t:l +daddr_t:i +dev_t:j +fd_mask:l +fsblkcnt64_t:y +fsblkcnt_t:m +fsfilcnt64_t:y +fsfilcnt_t:m +fsid_t:y +gid_t:j +id_t:j +ino64_t:y +ino_t:m +int16_t:s +int32_t:i +int64_t:x +int8_t:a +intptr_t:i +key_t:i +loff_t:x +mode_t:j +nlink_t:j +off64_t:x +off_t:l +pid_t:i +pthread_attr_t:14__pthread_attr +pthread_barrier_t:17__pthread_barrier +pthread_barrierattr_t:21__pthread_barrierattr +pthread_cond_t:14__pthread_cond +pthread_condattr_t:18__pthread_condattr +pthread_key_t:i +pthread_mutex_t:15__pthread_mutex +pthread_mutexattr_t:19__pthread_mutexattr +pthread_once_t:14__pthread_once +pthread_rwlock_t:16__pthread_rwlock +pthread_rwlockattr_t:20__pthread_rwlockattr +pthread_spinlock_t:i +pthread_t:i +quad_t:x +register_t:i +rlim64_t:y +rlim_t:m +sigset_t:m +size_t:j +socklen_t:j +ssize_t:i +suseconds_t:l +time_t:l +u_char:h +uid_t:j +uint:j +u_int:j +u_int16_t:t +u_int32_t:j +u_int64_t:y +u_int8_t:h +ulong:m +u_long:m +u_quad_t:y +useconds_t:j +ushort:t +u_short:t diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/dl-machine.h b/REORG.TODO/sysdeps/mach/hurd/i386/dl-machine.h new file mode 100644 index 0000000000..40f2ff29d4 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/dl-machine.h @@ -0,0 +1,7 @@ +/* Dynamic linker magic for Hurd/i386. + This file just gets us a call to _dl_first_init inserted + into the asm in sysdeps/i386/dl-machine.h that contains + the initializer code. */ + +#define RTLD_START_SPECIAL_INIT "call _dl_init_first@PLT; movl (%esp), %edx" +#include_next "dl-machine.h" diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/exc2signal.c b/REORG.TODO/sysdeps/mach/hurd/i386/exc2signal.c new file mode 100644 index 0000000000..a731da054c --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/exc2signal.c @@ -0,0 +1,165 @@ +/* Translate Mach exception codes into signal numbers. i386 version. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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_INVALID_ADDRESS + || detail->exc_code == KERN_PROTECTION_FAILURE + || detail->exc_code == KERN_WRITE_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_I386_INVOP) + detail->code = ILL_INVOPR_FAULT; + else if (detail->exc_code == EXC_I386_STKFLT) + detail->code = ILL_STACK_FAULT; + else + detail->code = 0; + break; + + case EXC_ARITHMETIC: + switch (detail->exc_code) + { + case EXC_I386_DIV: /* integer divide by zero */ + *signo = SIGFPE; + detail->code = FPE_INTDIV_FAULT; + break; + + case EXC_I386_INTO: /* integer overflow */ + *signo = SIGFPE; + detail->code = FPE_INTOVF_TRAP; + break; + + /* These aren't anywhere documented or used in Mach 3.0. */ + case EXC_I386_NOEXT: + case EXC_I386_EXTOVR: + default: + *signo = SIGFPE; + detail->code = 0; + break; + + case EXC_I386_EXTERR: + /* Subcode is the fp_status word saved by the hardware. + Give an error code corresponding to the first bit set. */ + if (detail->exc_subcode & FPS_IE) + { + *signo = SIGILL; + detail->code = ILL_FPEOPR_FAULT; + } + else if (detail->exc_subcode & FPS_DE) + { + *signo = SIGFPE; + detail->code = FPE_FLTDNR_FAULT; + } + else if (detail->exc_subcode & FPS_ZE) + { + *signo = SIGFPE; + detail->code = FPE_FLTDIV_FAULT; + } + else if (detail->exc_subcode & FPS_OE) + { + *signo = SIGFPE; + detail->code = FPE_FLTOVF_FAULT; + } + else if (detail->exc_subcode & FPS_UE) + { + *signo = SIGFPE; + detail->code = FPE_FLTUND_FAULT; + } + else if (detail->exc_subcode & FPS_PE) + { + *signo = SIGFPE; + detail->code = FPE_FLTINX_FAULT; + } + else + { + *signo = SIGFPE; + detail->code = 0; + } + break; + + /* These two can only be arithmetic exceptions if we + are in V86 mode, which sounds like emulation to me. + (See Mach 3.0 i386/trap.c.) */ + case EXC_I386_EMERR: + *signo = SIGFPE; + detail->code = FPE_EMERR_FAULT; + break; + case EXC_I386_BOUND: + *signo = SIGFPE; + detail->code = FPE_EMBND_FAULT; + 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: + /* The only time we get this in Mach 3.0 + is for an out of bounds trap. */ + if (detail->exc_code == EXC_I386_BOUND) + { + *signo = SIGFPE; + detail->code = FPE_SUBRNG_FAULT; + } + else + { + *signo = SIGEMT; + detail->code = 0; + } + break; + + case EXC_BREAKPOINT: + *signo = SIGTRAP; + if (detail->exc_code == EXC_I386_SGL) + detail->code = DBG_SINGLE_TRAP; + else if (detail->exc_code == EXC_I386_BPT) + detail->code = DBG_BRKPNT_FAULT; + else + detail->code = 0; + break; + } +} diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/init-first.c b/REORG.TODO/sysdeps/mach/hurd/i386/init-first.c new file mode 100644 index 0000000000..6a6a694719 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/init-first.c @@ -0,0 +1,410 @@ +/* Initialization code run first thing by the ELF startup code. For i386/Hurd. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <ctype.h> +#include <hurd.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sysdep.h> +#include <set-hooks.h> +#include "hurdstartup.h" +#include "hurdmalloc.h" /* XXX */ +#include "../locale/localeinfo.h" + +#include <ldsodefs.h> +#include <fpu_control.h> + +extern void __mach_init (void); +extern void __init_misc (int, char **, char **); +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; + +#ifndef SHARED +int __libc_enable_secure; +#endif +int __libc_multiple_libcs attribute_hidden = 1; + +extern int __libc_argc attribute_hidden; +extern char **__libc_argv attribute_hidden; +extern char **_dl_argv; + +extern void *(*_cthread_init_routine) (void) __attribute__ ((weak)); +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)); + + +/* We call this once the Hurd magic is all set up and we are ready to be a + Posixoid program. This does the same things the generic version does. */ +static void +posixland_init (int argc, char **argv, char **envp) +{ + __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; + + /* Make sure we don't initialize twice. */ + if (!__libc_multiple_libcs) + { + /* Set the FPU control word to the proper default value. */ + __setfpucw (__fpu_control); + } + else + { + /* Initialize data structures so the additional libc can do RPCs. */ + __mach_init (); + } + + /* Save the command-line arguments. */ + __libc_argc = argc; + __libc_argv = argv; + __environ = envp; + +#ifndef SHARED + _dl_non_dynamic_init (); +#endif + __init_misc (argc, argv, envp); + + /* Initialize ctype data. */ + __ctype_init (); + +#if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS + __libc_global_ctors (); +#endif +} + + +static void +init1 (int argc, char *arg0, ...) +{ + char **argv = &arg0; + char **envp = &argv[argc + 1]; + struct hurd_startup_data *d; + + 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]) + { +#ifndef SHARED + /* With a new enough linker (binutils-2.23 or better), + the magic __ehdr_start symbol will be available and + __libc_start_main will have done this that way already. */ + if (_dl_phdr == NULL) + { + /* We may need to see our own phdrs, e.g. for TLS setup. + Try the usual kludge to find the headers without help from + the exec server. */ + extern const void __executable_start; + const ElfW(Ehdr) *const ehdr = &__executable_start; + _dl_phdr = (const void *) ehdr + ehdr->e_phoff; + _dl_phnum = ehdr->e_phnum; + assert (ehdr->e_phentsize == sizeof (ElfW(Phdr))); + } +#endif + return; + } + +#ifndef SHARED + __libc_enable_secure = d->flags & EXEC_SECURE; + + _dl_phdr = (ElfW(Phdr) *) d->phdr; + _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr)); + assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0); +#endif + + _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 (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); +} + + +static inline void +init (int *data) +{ + int argc = *data; + char **argv = (void *) (data + 1); + char **envp = &argv[argc + 1]; + struct hurd_startup_data *d; + unsigned long int threadvars[_HURD_THREADVAR_MAX]; + + /* Provide temporary storage for thread-specific variables on the + startup stack so the cthreads initialization code can use them + for malloc et al, or so we can use malloc below for the real + threadvars array. */ + memset (threadvars, 0, sizeof threadvars); + threadvars[_HURD_THREADVAR_LOCALE] = (unsigned long int) &_nl_global_locale; + __hurd_threadvar_stack_offset = (unsigned long int) threadvars; + + /* Since the cthreads initialization code uses malloc, and the + malloc initialization code needs to get at the environment, make + sure we can find it. We'll need to do this again later on since + switching stacks changes the location where the environment is + stored. */ + __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 && _cthread_init_routine) + { + /* Initialize cthreads, which will allocate us a new stack to run on. */ + int *newsp = (*_cthread_init_routine) (); + struct hurd_startup_data *od; + + void switch_stacks (void); + + __libc_stack_end = newsp; + + /* Copy per-thread variables from that temporary + area onto the new cthread stack. */ + memcpy (__hurd_threadvar_location_from_sp (0, newsp), + threadvars, sizeof threadvars); + + /* Copy the argdata from the old stack to the new one. */ + newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data, + (char *) d - (char *) data); + +#ifdef SHARED + /* And readjust the dynamic linker's idea of where the argument + vector lives. */ + assert (_dl_argv == argv); + _dl_argv = (void *) (newsp + 1); +#endif + + /* Set up the Hurd startup data block immediately following + the argument and environment pointers on the new stack. */ + od = ((void *) 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. */ + /* The following expression would typically be written as + ``__builtin_return_address (0)''. But, for example, GCC 4.4.6 doesn't + recognize that this read operation may alias the following write + operation, and thus is free to reorder the two, clobbering the + original return address. */ + *--newsp = *((int *) __builtin_frame_address (0) + 1); + /* GCC 4.4.6 also wants us to force loading *NEWSP already here. */ + asm volatile ("# %0" : : "X" (*newsp)); + *((void **) __builtin_frame_address (0) + 1) = &switch_stacks; + /* Force NEWSP into %eax and &init1 into %ecx, which are not restored + by function return. */ + asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1)); + } + else + { + /* 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 *array; + unsigned int i; + int usercode; + + void call_init1 (void); + + array = malloc (__hurd_threadvar_max * sizeof (unsigned long int)); + if (array == NULL) + __libc_fatal ("Can't allocate single-threaded thread variables."); + + /* Copy per-thread variables from the temporary array into the + newly malloc'd space. */ + memcpy (array, threadvars, sizeof threadvars); + __hurd_threadvar_stack_offset = (unsigned long int) array; + for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i) + array[i] = 0; + + /* The argument data is just above the stack frame we will unwind by + returning. Mutate our own return address to run the code below. */ + /* The following expression would typically be written as + ``__builtin_return_address (0)''. But, for example, GCC 4.4.6 doesn't + recognize that this read operation may alias the following write + operation, and thus is free to reorder the two, clobbering the + original return address. */ + usercode = *((int *) __builtin_frame_address (0) + 1); + /* GCC 4.4.6 also wants us to force loading USERCODE already here. */ + asm volatile ("# %0" : : "X" (usercode)); + *((void **) __builtin_frame_address (0) + 1) = &call_init1; + /* Force USERCODE into %eax and &init1 into %ecx, which are not + restored by function return. */ + asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1)); + } +} + +/* These bits of inline assembler used to be located inside `init'. + However they were optimized away by gcc 2.95. */ + +/* The return address of `init' above, was redirected to here, so at + this point our stack is unwound and callers' registers restored. + Only %ecx and %eax are call-clobbered and thus still have the + values we set just above. Fetch from there the new stack pointer + we will run on, and jmp to the run-time address of `init1'; when it + returns, it will run the user code with the argument data at the + top of the stack. */ +asm ("switch_stacks:\n" + " movl %eax, %esp\n" + " jmp *%ecx"); + +/* As in the stack-switching case, at this point our stack is unwound + and callers' registers restored, and only %ecx and %eax communicate + values from the lines above. In this case we have stashed in %eax + the user code return address. Push it on the top of the stack so + it acts as init1's return address, and then jump there. */ +asm ("call_init1:\n" + " push %eax\n" + " jmp *%ecx\n"); + + +/* Do the first essential initializations that must precede all else. */ +static inline void +first_init (void) +{ + /* Initialize data structures so we can do RPCs. */ + __mach_init (); + + RUN_HOOK (_hurd_preinit_hook, ()); +} + +#ifdef SHARED +/* This function is called specially by the dynamic linker to do early + initialization of the shared C library before normal initializers + expecting a Posixoid environment can run. It gets called with the + stack set up just as the user will see it, so it can switch stacks. */ + +void +_dl_init_first (int argc, ...) +{ + first_init (); + + /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets confused. */ + init (&argc); +} +#endif + + +#ifdef SHARED +/* The regular posixland initialization is what goes into libc's + normal initializer. */ +/* 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!! */ +strong_alias (posixland_init, _init); + +void +__libc_init_first (int argc, char **argv, char **envp) +{ + /* Everything was done in the shared library initializer, _init. */ +} +#else +strong_alias (posixland_init, __libc_init_first); + + +/* XXX This is all a crock and I am not happy with it. + This poorly-named function is called by static-start.S, + which should not exist at all. */ +void +_hurd_stack_setup (void) +{ + intptr_t caller = (intptr_t) __builtin_return_address (0); + + void doinit (intptr_t *data) + { + /* This function gets called with the argument data at TOS. */ + void doinit1 (int argc, ...) + { + /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets + confused. */ + init ((int *) &argc); + } + + /* 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 `doinit1' with the argument data already on the + stack. */ + *--data = caller; + asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack. */ + "movl $0, %%ebp\n" /* Clear outermost frame pointer. */ + "jmp *%1" : : "r" (data), "r" (&doinit1) : "sp"); + /* NOTREACHED */ + } + + first_init (); + + _hurd_startup ((void **) __builtin_frame_address (0) + 2, &doinit); +} +#endif + + +/* This function is defined here so that if this file ever gets into + ld.so we will get a link error. Having this file silently included + in ld.so causes disaster, because the _init definition above will + cause ld.so to gain an init function, which is not a cool thing. */ + +void +_dl_start (void) +{ + abort (); +} diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/intr-msg.h b/REORG.TODO/sysdeps/mach/hurd/i386/intr-msg.h new file mode 100644 index 0000000000..43cd79bc28 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/intr-msg.h @@ -0,0 +1,112 @@ +/* Machine-dependent details of interruptible RPC messaging. i386 version. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + + +/* Note that we must mark OPTION and TIMEOUT as outputs of this operation, + to indicate that the signal thread might mutate them as part + of sending us to a signal handler. */ +#define INTR_MSG_TRAP(msg, option, send_size, rcv_size, rcv_name, timeout, notify) \ +({ \ + error_t err; \ + asm (".globl _hurd_intr_rpc_msg_do_trap\n" \ + ".globl _hurd_intr_rpc_msg_in_trap\n" \ + ".globl _hurd_intr_rpc_msg_cx_sp\n" \ + ".globl _hurd_intr_rpc_msg_sp_restored\n" \ + " movl %%esp, %%ecx\n" \ + " leal %3, %%esp\n" \ + "_hurd_intr_rpc_msg_cx_sp: movl $-25, %%eax\n" \ + "_hurd_intr_rpc_msg_do_trap: lcall $7, $0 # status in %0\n" \ + "_hurd_intr_rpc_msg_in_trap: movl %%ecx, %%esp\n" \ + "_hurd_intr_rpc_msg_sp_restored:" \ + : "=a" (err), "+m" (option), "+m" (timeout) \ + : "m" ((&msg)[-1]) \ + : "ecx"); \ + err; \ +}) + + +static void inline +INTR_MSG_BACK_OUT (struct i386_thread_state *state) +{ + extern const void _hurd_intr_rpc_msg_cx_sp; + if (state->eip >= (natural_t) &_hurd_intr_rpc_msg_cx_sp) + state->uesp = state->ecx; + else + state->ecx = state->uesp; +} + +#include "hurdfault.h" + +/* This cannot be an inline function because it calls setjmp. */ +#define SYSCALL_EXAMINE(state, callno) \ +({ \ + struct { unsigned int c[2]; } *p = (void *) ((state)->eip - 7); \ + int result; \ + if (_hurdsig_catch_memory_fault (p)) \ + return 0; \ + if (result = p->c[0] == 0x0000009a && (p->c[1] & 0x00ffffff) == 0x00000700) \ + /* The PC is just after an `lcall $7,$0' instruction. \ + This is a system call in progress; %eax holds the call number. */ \ + *(callno) = (state)->eax; \ + _hurdsig_end_catch_fault (); \ + result; \ +}) + + +struct mach_msg_trap_args + { + void *retaddr; /* Address mach_msg_trap will return to. */ + /* 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; + }; + + +/* This cannot be an inline function because it calls setjmp. */ +#define MSG_EXAMINE(state, msgid, rcvname, send_name, opt, tmout) \ +({ \ + const struct mach_msg_trap_args *args = (const void *) (state)->uesp; \ + mach_msg_header_t *msg; \ + _hurdsig_catch_memory_fault (args) ? -1 : \ + ({ \ + msg = args->msg; \ + *(opt) = args->option; \ + *(tmout) = args->timeout; \ + *(rcvname) = args->rcv_name; \ + _hurdsig_end_catch_fault (); \ + if (msg == 0) \ + { \ + *(send_name) = MACH_PORT_NULL; \ + *(msgid) = 0; \ + } \ + else \ + { \ + if (_hurdsig_catch_memory_fault (msg)) \ + return -1; \ + *(send_name) = msg->msgh_remote_port; \ + *(msgid) = msg->msgh_id; \ + _hurdsig_end_catch_fault (); \ + } \ + 0; \ + }); \ +}) diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/ioperm.c b/REORG.TODO/sysdeps/mach/hurd/i386/ioperm.c new file mode 100644 index 0000000000..c3dc1a3354 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/ioperm.c @@ -0,0 +1,53 @@ +/* Access to hardware i/o ports. Hurd/x86 version. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/io.h> +#include <hurd.h> +#include <mach/i386/mach_i386.h> + +int +ioperm (unsigned long int from, unsigned long int num, int turn_on) +{ +#if ! HAVE_I386_IO_PERM_MODIFY + return __hurd_fail (ENOSYS); +#else + error_t err; + device_t devmaster; + + /* With the device master port we get a capability that represents + this range of io ports. */ + err = __get_privileged_ports (NULL, &devmaster); + if (! err) + { + io_perm_t perm; + err = __i386_io_perm_create (devmaster, from, from + num - 1, &perm); + __mach_port_deallocate (__mach_task_self (), devmaster); + if (! err) + { + /* Now we add or remove that set from our task's bitmap. */ + err = __i386_io_perm_modify (__mach_task_self (), perm, turn_on); + __mach_port_deallocate (__mach_task_self (), perm); + } + + if (err == MIG_BAD_ID) /* Old kernels don't have these RPCs. */ + err = ENOSYS; + } + + return err ? __hurd_fail (err) : 0; +#endif +} diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/longjmp-ts.c b/REORG.TODO/sysdeps/mach/hurd/i386/longjmp-ts.c new file mode 100644 index 0000000000..ef84c665ec --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/longjmp-ts.c @@ -0,0 +1,39 @@ +/* Perform a `longjmp' on a Mach thread_state. i386 version. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <hurd/signal.h> +#include <setjmp.h> +#include <jmpbuf-offsets.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 i386_thread_state *ts = state; + + ts->ebx = env[0].__jmpbuf[JB_BX]; + ts->esi = env[0].__jmpbuf[JB_SI]; + ts->edi = env[0].__jmpbuf[JB_DI]; + ts->ebp = env[0].__jmpbuf[JB_BP]; + ts->uesp = env[0].__jmpbuf[JB_SP]; + ts->eip = env[0].__jmpbuf[JB_PC]; + ts->eax = val ?: 1; +} diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/sigcontextinfo.h b/REORG.TODO/sysdeps/mach/hurd/i386/sigcontextinfo.h new file mode 100644 index 0000000000..a8be1455d5 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/sigcontextinfo.h @@ -0,0 +1,24 @@ +/* Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define SIGCONTEXT struct sigcontext +#define SIGCONTEXT_EXTRA_ARGS +#define GET_PC(ctx) ((void *) (ctx).sc_eip) +#define GET_FRAME(ctx) ((void *) (ctx).sc_ebp) +#define GET_STACK(ctx) ((void *) (ctx).sc_uesp) +#define CALL_SIGHANDLER(handler, signo, ctx) \ + (handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx)) diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/signal-defines.sym b/REORG.TODO/sysdeps/mach/hurd/i386/signal-defines.sym new file mode 100644 index 0000000000..e42bbbe061 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/signal-defines.sym @@ -0,0 +1,10 @@ +#include <hurd/signal.h> +#include <signal.h> + +-- + +HURD_SIGSTATE__SIGALTSTACK__OFFSET offsetof(struct hurd_sigstate, sigaltstack) + +SIGALTSTACK__SS_SP__OFFSET offsetof(stack_t, ss_sp) +SIGALTSTACK__SS_SIZE__OFFSET offsetof(stack_t, ss_size) +SIGALTSTACK__SS_FLAGS__OFFSET offsetof(stack_t, ss_flags) diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/sigreturn.c b/REORG.TODO/sysdeps/mach/hurd/i386/sigreturn.c new file mode 100644 index 0000000000..ce0f656ff0 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/sigreturn.c @@ -0,0 +1,139 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +register int *sp asm ("%esp"); + +#include <hurd.h> +#include <hurd/signal.h> +#include <hurd/threadvar.h> +#include <hurd/msg.h> +#include <stdlib.h> +#include <string.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. + If it did return, the pending signal didn't run a handler; + proceed as usual. */ + __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_fpused) + /* Restore the FPU state. Mach conveniently stores the state + in the format the i387 `frstor' instruction uses to restore it. */ + asm volatile ("frstor %0" : : "m" (scp->sc_fpsave)); + + { + /* There are convenient instructions to pop state off the stack, so we + copy the registers onto the user's stack, switch there, pop and + return. */ + + int *usp = (int *) scp->sc_uesp; + + *--usp = scp->sc_eip; + *--usp = scp->sc_efl; + memcpy (usp -= 12, &scp->sc_i386_thread_state, 12 * sizeof (int)); + + sp = usp; + +#define A(line) asm volatile (#line) + /* The members in the sigcontext are arranged in this order + so we can pop them easily. */ + + /* Pop the segment registers (except %cs and %ss, done last). */ + A (popl %gs); + A (popl %fs); + A (popl %es); + A (popl %ds); + /* Pop the general registers. */ + A (popa); + /* Pop the processor flags. */ + A (popf); + /* Return to the saved PC. */ + A (ret); + + /* Firewall. */ + A (hlt); +#undef A + } + + /* NOTREACHED */ + return -1; +} + +weak_alias (__sigreturn, sigreturn) diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/static-start.S b/REORG.TODO/sysdeps/mach/hurd/i386/static-start.S new file mode 100644 index 0000000000..03eb204f9d --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/static-start.S @@ -0,0 +1,27 @@ +/* Startup code for statically linked Hurd/i386 binaries. + Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + + .text + .globl _start +_start: + call _hurd_stack_setup + xorl %edx, %edx + jmp _start1 + +#define _start _start1 +#include <sysdeps/i386/start.S> diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/sys/io.h b/REORG.TODO/sysdeps/mach/hurd/i386/sys/io.h new file mode 100644 index 0000000000..9f3dbfffa7 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/sys/io.h @@ -0,0 +1,177 @@ +/* Access to hardware i/o ports. GNU/x86 version. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (unsigned long int __from, unsigned long int __num, + int __turn_on) __THROW; + +/* Set the I/O privilege level to LEVEL. If LEVEL>3, permission to + access any I/O port is granted. This call requires root + privileges. */ +extern int iopl (int __level) __THROW; + +#if defined __GNUC__ && __GNUC__ >= 2 + +static __inline unsigned char +inb (unsigned short int port) +{ + unsigned char _v; + + __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline unsigned char +inb_p (unsigned short int port) +{ + unsigned char _v; + + __asm__ __volatile__ ("inb %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline unsigned short int +inw (unsigned short int port) +{ + unsigned short _v; + + __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline unsigned short int +inw_p (unsigned short int port) +{ + unsigned short int _v; + + __asm__ __volatile__ ("inw %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline unsigned int +inl (unsigned short int port) +{ + unsigned int _v; + + __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline unsigned int +inl_p (unsigned short int port) +{ + unsigned int _v; + __asm__ __volatile__ ("inl %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +static __inline void +outb (unsigned char value, unsigned short int port) +{ + __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (port)); +} + +static __inline void +outb_p (unsigned char value, unsigned short int port) +{ + __asm__ __volatile__ ("outb %b0,%w1\noutb %%al,$0x80": :"a" (value), + "Nd" (port)); +} + +static __inline void +outw (unsigned short int value, unsigned short int port) +{ + __asm__ __volatile__ ("outw %w0,%w1": :"a" (value), "Nd" (port)); + +} + +static __inline void +outw_p (unsigned short int value, unsigned short int port) +{ + __asm__ __volatile__ ("outw %w0,%w1\noutb %%al,$0x80": :"a" (value), + "Nd" (port)); +} + +static __inline void +outl (unsigned int value, unsigned short int port) +{ + __asm__ __volatile__ ("outl %0,%w1": :"a" (value), "Nd" (port)); +} + +static __inline void +outl_p (unsigned int value, unsigned short int port) +{ + __asm__ __volatile__ ("outl %0,%w1\noutb %%al,$0x80": :"a" (value), + "Nd" (port)); +} + +static __inline void +insb (unsigned short int port, void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; insb":"=D" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +static __inline void +insw (unsigned short int port, void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; insw":"=D" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +static __inline void +insl (unsigned short int port, void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; insl":"=D" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +static __inline void +outsb (unsigned short int port, const void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; outsb":"=S" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +static __inline void +outsw (unsigned short int port, const void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; outsw":"=S" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +static __inline void +outsl (unsigned short int port, const void *addr, unsigned long int count) +{ + __asm__ __volatile__ ("cld ; rep ; outsl":"=S" (addr), + "=c" (count):"d" (port), "0" (addr), "1" (count)); +} + +#endif /* GNU C */ + +__END_DECLS +#endif /* _SYS_IO_H */ diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/tls.h b/REORG.TODO/sysdeps/mach/hurd/i386/tls.h new file mode 100644 index 0000000000..74b444ef19 --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/tls.h @@ -0,0 +1,169 @@ +/* Definitions for thread-local data handling. Hurd/i386 version. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _I386_TLS_H +#define _I386_TLS_H + + +/* Some things really need not be machine-dependent. */ +#include <sysdeps/mach/hurd/tls.h> + + +#ifndef __ASSEMBLER__ +# include <dl-dtv.h> + +/* Type of the TCB. */ +typedef struct +{ + void *tcb; /* Points to this structure. */ + dtv_t *dtv; /* Vector of pointers to TLS data. */ + thread_t self; /* This thread's control port. */ + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; + uintptr_t pointer_guard; + int gscope_flag; + int private_futex; + /* Reservation of some values for the TM ABI. */ + void *__private_tm[4]; + /* GCC split stack support. */ + void *__private_ss; +} tcbhead_t; +#endif + + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +#define TLS_TCB_AT_TP 1 +#define TLS_DTV_AT_TP 0 + +#ifndef __ASSEMBLER__ + +/* Use i386-specific RPCs to arrange that %gs segment register prefix + addresses the TCB in each thread. */ +# include <mach/i386/mach_i386.h> + +# ifndef HAVE_I386_SET_GDT +# define __i386_set_gdt(thr, sel, desc) ((void) (thr), (void) (sel), (void) (desc), MIG_BAD_ID) +# endif + +# include <errno.h> +# include <assert.h> + +# define HURD_TLS_DESC_DECL(desc, tcb) \ + struct descriptor desc = \ + { /* low word: */ \ + 0xffff /* limit 0..15 */ \ + | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \ + , /* high word: */ \ + ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \ + | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \ + | (0xf << 16) /* limit 16..19 */ \ + | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \ + | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \ + } + + +static inline const char * __attribute__ ((unused)) +_hurd_tls_init (tcbhead_t *tcb) +{ + HURD_TLS_DESC_DECL (desc, tcb); + + /* This field is used by TLS accesses to get our "thread pointer" + from the TLS point of view. */ + tcb->tcb = tcb; + + /* Cache our thread port. */ + tcb->self = __mach_thread_self (); + + /* Get the first available selector. */ + int sel = -1; + error_t err = __i386_set_gdt (tcb->self, &sel, desc); + if (err == MIG_BAD_ID) + { + /* Old kernel, use a per-thread LDT. */ + sel = 0x27; + err = __i386_set_ldt (tcb->self, sel, &desc, 1); + assert_perror (err); + if (err) + return "i386_set_ldt failed"; + } + else if (err) + { + assert_perror (err); /* Separate from above with different line #. */ + return "i386_set_gdt failed"; + } + + /* Now install the new selector. */ + asm volatile ("mov %w0, %%gs" :: "q" (sel)); + + return 0; +} + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(descr) \ + _hurd_tls_init ((tcbhead_t *) (descr)) + +/* Return the TCB address of the current thread. */ +# define THREAD_SELF \ + ({ tcbhead_t *__tcb; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__tcb) \ + : "i" (offsetof (tcbhead_t, tcb))); \ + __tcb;}) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ asm volatile ("movl %0,%%gs:%P1" \ + : : "ir" (dtvp), "i" (offsetof (tcbhead_t, dtv))); }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ dtv_t *_dtv; \ + asm ("movl %%gs:%P1,%0" : "=q" (_dtv) : "i" (offsetof (tcbhead_t, dtv)));\ + _dtv; }) + +# include <mach/machine/thread_status.h> + +/* Set up TLS in the new thread of a fork child, copying from our own. */ +static inline error_t __attribute__ ((unused)) +_hurd_tls_fork (thread_t child, struct i386_thread_state *state) +{ + /* Fetch the selector set by _hurd_tls_init. */ + int sel; + asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0)); + if (sel == state->ds) /* _hurd_tls_init was never called. */ + return 0; + + tcbhead_t *const tcb = THREAD_SELF; + HURD_TLS_DESC_DECL (desc, tcb); + error_t err; + + if (__builtin_expect (sel, 0x50) & 4) /* LDT selector */ + err = __i386_set_ldt (child, sel, &desc, 1); + else + err = __i386_set_gdt (child, &sel, desc); + + state->gs = sel; + return err; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* i386/tls.h */ diff --git a/REORG.TODO/sysdeps/mach/hurd/i386/trampoline.c b/REORG.TODO/sysdeps/mach/hurd/i386/trampoline.c new file mode 100644 index 0000000000..002415929c --- /dev/null +++ b/REORG.TODO/sysdeps/mach/hurd/i386/trampoline.c @@ -0,0 +1,265 @@ +/* Set thread_state for sighandler, and sigcontext to recover. i386 version. + Copyright (C) 1994-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <hurd/signal.h> +#include <hurd/userlink.h> +#include <thread_state.h> +#include <mach/machine/eflags.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) +{ + void trampoline (void); + void rpc_wait_trampoline (void); + void firewall (void); + extern const void _hurd_intr_rpc_msg_cx_sp; + extern const void _hurd_intr_rpc_msg_sp_restored; + 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_i386_thread_state, + sizeof (state->basic)); + memcpy (&state->fpu, &ss->context->sc_i386_float_state, + sizeof (state->fpu)); + state->set |= (1 << i386_THREAD_STATE) | (1 << i386_FLOAT_STATE); + } + } + + if (! machine_get_basic_state (ss->thread, state)) + return NULL; + + /* Save the original SP in the gratuitous `esp' slot. + We may need to reset the SP (the `uesp' slot) to avoid clobbering an + interrupted RPC frame. */ + state->basic.esp = state->basic.uesp; + + 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. */ + } + /* This code has intimate knowledge of the special mach_msg system call + done in intr-msg.c; that code does (see intr-msg.h): + movl %esp, %ecx + leal ARGS, %esp + _hurd_intr_rpc_msg_cx_sp: movl $-25, %eax + _hurd_intr_rpc_msg_do_trap: lcall $7, $0 + _hurd_intr_rpc_msg_in_trap: movl %ecx, %esp + _hurd_intr_rpc_msg_sp_restored: + We must check for the window during which %esp points at the + mach_msg arguments. The space below until %ecx is used by + the _hurd_intr_rpc_mach_msg frame, and must not be clobbered. */ + else if (state->basic.eip >= (int) &_hurd_intr_rpc_msg_cx_sp && + state->basic.eip < (int) &_hurd_intr_rpc_msg_sp_restored) + /* The SP now points at the mach_msg args, but there is more stack + space used below it. The real SP is saved in %ecx; we must push the + new frame below there, and restore that value as the SP on + sigreturn. */ + sigsp = (char *) (state->basic.uesp = state->basic.ecx); + else + sigsp = (char *) state->basic.uesp; + + /* 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_gs mimics a + struct i386_thread_state. */ + memcpy (&scp->sc_i386_thread_state, + &state->basic, sizeof (state->basic)); + + /* struct sigcontext is laid out so that starting at sc_fpkind mimics + a struct i386_float_state. */ + ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE, + &state->fpu, &scp->sc_i386_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 on its stack to enable only + message reception, since the request message has already been + sent. */ + + struct mach_msg_trap_args *args = (void *) state->basic.esp; + + 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.eip = (int) rpc_wait_trampoline; + /* The reply-receiving trampoline code runs initially on the original + user stack. We pass it the signal stack pointer in %ebx. */ + state->basic.uesp = state->basic.esp; /* Restore mach_msg syscall SP. */ + state->basic.ebx = (int) sigsp; + /* After doing the message receive, the trampoline code will need to + update the %eax 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 %ecx. */ + state->basic.ecx = (int) &scp->sc_eax; + } + else + { + state->basic.eip = (int) trampoline; + state->basic.uesp = (int) sigsp; + } + /* We pass the handler function to the trampoline code in %edx. */ + state->basic.edx = (int) handler; + + /* The x86 ABI says the DF bit is clear on entry to any function. */ + state->basic.efl &= ~EFL_DF; + + return scp; +} + +/* The trampoline code follows. This used to be located inside + _hurd_setup_sighandler, but was optimized away by gcc 2.95. */ + +asm ("rpc_wait_trampoline:\n"); + /* 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 on our stack. The interrupted user + stack pointer has not been changed, so the system call can find its + arguments; the signal stack pointer is in %ebx. For our convenience, + %ecx points to the sc_eax member of the sigcontext. */ +asm (/* Retry the interrupted mach_msg system call. */ + "movl $-25, %eax\n" /* mach_msg_trap */ + "lcall $7, $0\n" + /* When the sigcontext was saved, %eax 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 %eax. So + store the new %eax value into the sc_eax member of the sigcontext + (whose address is in %ecx to make this code simpler). */ + "movl %eax, (%ecx)\n" + /* Switch to the signal stack. */ + "movl %ebx, %esp\n"); + + asm ("trampoline:\n"); + /* Entry point for running the handler normally. The arguments to the + handler function are already on the top of the stack: + + 0(%esp) SIGNO + 4(%esp) SIGCODE + 8(%esp) SCP + */ +asm ("call *%edx\n" /* Call the handler function. */ + "addl $12, %esp\n" /* Pop its args. */ + /* The word at the top of stack is &__sigreturn; following are a dummy + word to fill the slot for the address for __sigreturn to return to, + and a copy of SCP for __sigreturn's argument. "Return" to calling + __sigreturn (SCP); this call never returns. */ + "ret"); + +asm ("firewall:\n" + "hlt"); |