1 /* Machine-dependent details of interruptible RPC messaging.  i386 version.
2    Copyright (C) 1995-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 
20 /* Note that we must mark OPTION and TIMEOUT as outputs of this operation,
21    to indicate that the signal thread might mutate them as part
22    of sending us to a signal handler.  */
23 
24 #define INTR_MSG_TRAP(msg, option, send_size, rcv_size, rcv_name, timeout, notify, cancel_p, intr_port_p) \
25 ({									      \
26   error_t err;								      \
27   asm (".globl _hurd_intr_rpc_msg_about_to\n"				      \
28        ".globl _hurd_intr_rpc_msg_cx_sp\n"				      \
29        ".globl _hurd_intr_rpc_msg_do_trap\n" 				      \
30        ".globl _hurd_intr_rpc_msg_in_trap\n"				      \
31        ".globl _hurd_intr_rpc_msg_sp_restored\n"			      \
32        "_hurd_intr_rpc_msg_about_to:"					      \
33        /* We need to make a last check of cancel, in case we got interrupted
34           right before _hurd_intr_rpc_msg_about_to.  */			      \
35        "				cmpl $0, %5\n"			      \
36        "				jz _hurd_intr_rpc_msg_do\n"	      \
37        /* We got interrupted, note so and return EINTR.  */		      \
38        "				movl $0, %3\n"			      \
39        "				movl %6, %%eax\n"		      \
40        "				jmp _hurd_intr_rpc_msg_sp_restored\n" \
41        "_hurd_intr_rpc_msg_do:"						      \
42        /* Ok, push the mach_msg_trap arguments.  */			      \
43        "				pushl 24(%4)\n"			      \
44        "				.cfi_adjust_cfa_offset 4\n"	      \
45        "				pushl %2\n"			      \
46        "				.cfi_adjust_cfa_offset 4\n"	      \
47        "				pushl 16(%4)\n"			      \
48        "				.cfi_adjust_cfa_offset 4\n"	      \
49        "				pushl 12(%4)\n"			      \
50        "				.cfi_adjust_cfa_offset 4\n"	      \
51        "				pushl 8(%4)\n"			      \
52        "				.cfi_adjust_cfa_offset 4\n"	      \
53        "				pushl %1\n"			      \
54        "				.cfi_adjust_cfa_offset 4\n"	      \
55        "				pushl (%4)\n"			      \
56        "				.cfi_adjust_cfa_offset 4\n"	      \
57        "				pushl $0\n"			      \
58        "				.cfi_adjust_cfa_offset 4\n"	      \
59        /* TODO: remove this ecx kludge, we don't need it any more */	      \
60        "				movl %%esp, %%ecx\n"		      \
61        "_hurd_intr_rpc_msg_cx_sp:	movl $-25, %%eax\n"		      \
62        "_hurd_intr_rpc_msg_do_trap:	lcall $7, $0 # status in %0\n"	      \
63        "_hurd_intr_rpc_msg_in_trap:"					      \
64        /* Ok, clean the arguments and update OPTION and TIMEOUT.  */	      \
65        "				addl $8, %%esp\n"		      \
66        "				.cfi_adjust_cfa_offset -8\n"	      \
67        "				popl %1\n"			      \
68        "				.cfi_adjust_cfa_offset -4\n"	      \
69        "				addl $12, %%esp\n"		      \
70        "				.cfi_adjust_cfa_offset -12\n"	      \
71        "				popl %2\n"			      \
72        "				.cfi_adjust_cfa_offset -4\n"	      \
73        "				addl $4, %%esp\n"		      \
74        "				.cfi_adjust_cfa_offset -4\n"	      \
75        "_hurd_intr_rpc_msg_sp_restored:"				      \
76        : "=a" (err), "+r" (option), "+r" (timeout), "=m" (*intr_port_p)	      \
77        : "r" (&msg), "m" (*cancel_p), "i" (EINTR)			      \
78        : "ecx");							      \
79   err;									      \
80 })
81 
82 
83 static void inline
INTR_MSG_BACK_OUT(struct i386_thread_state * state)84 INTR_MSG_BACK_OUT (struct i386_thread_state *state)
85 {
86   extern const void _hurd_intr_rpc_msg_cx_sp;
87   if (state->eip >= (natural_t) &_hurd_intr_rpc_msg_cx_sp)
88     state->uesp = state->ecx;
89   else
90     state->ecx = state->uesp;
91 }
92 
93 #include "hurdfault.h"
94 
95 /* This cannot be an inline function because it calls setjmp.  */
96 #define SYSCALL_EXAMINE(state, callno)					      \
97 ({									      \
98   struct { unsigned int c[2]; } *p = (void *) ((state)->eip - 7);	      \
99   int result;								      \
100   if (_hurdsig_catch_memory_fault (p))					      \
101     return 0;								      \
102   if (result = p->c[0] == 0x0000009a && (p->c[1] & 0x00ffffff) == 0x00000700) \
103     /* The PC is just after an `lcall $7,$0' instruction.		      \
104        This is a system call in progress; %eax holds the call number.  */     \
105     *(callno) = (state)->eax;						      \
106   _hurdsig_end_catch_fault ();						      \
107   result;								      \
108 })
109 
110 
111 struct mach_msg_trap_args
112   {
113     void *retaddr;		/* Address mach_msg_trap will return to.  */
114     /* This is the order of arguments to mach_msg_trap.  */
115     mach_msg_header_t *msg;
116     mach_msg_option_t option;
117     mach_msg_size_t send_size;
118     mach_msg_size_t rcv_size;
119     mach_port_t rcv_name;
120     mach_msg_timeout_t timeout;
121     mach_port_t notify;
122   };
123 
124 
125 /* This cannot be an inline function because it calls setjmp.  */
126 #define MSG_EXAMINE(state, msgid, rcvname, send_name, opt, tmout)	      \
127 ({									      \
128   const struct mach_msg_trap_args *args = (const void *) (state)->uesp;	      \
129   mach_msg_header_t *msg;						      \
130   _hurdsig_catch_memory_fault (args) ? -1 :				      \
131     ({									      \
132       msg = args->msg;							      \
133       *(opt) = args->option;						      \
134       *(tmout) = args->timeout;						      \
135       *(rcvname) = args->rcv_name;					      \
136       _hurdsig_end_catch_fault ();					      \
137       if (msg == 0)							      \
138 	{								      \
139 	  *(send_name) = MACH_PORT_NULL;				      \
140 	  *(msgid) = 0;							      \
141 	}								      \
142       else								      \
143 	{								      \
144 	  if (_hurdsig_catch_memory_fault (msg))			      \
145 	    return -1;							      \
146 	  *(send_name) = msg->msgh_remote_port;				      \
147 	  *(msgid) = msg->msgh_id;					      \
148 	  _hurdsig_end_catch_fault ();					      \
149 	}								      \
150       0;								      \
151     });									      \
152 })
153