summaryrefslogtreecommitdiff
path: root/hurd/thread.h
blob: 1ca8ebeab352887ef28dd0d161b612c498653f03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/* thread.h - Thread definitions.
   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   GNU Hurd 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 3 of the
   License, or (at your option) any later version.

   GNU Hurd 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 GNU Hurd.  If not, see
   <http://www.gnu.org/licenses/>.  */

#ifndef __have_activation_frame
# define __have_activation_frame

# include <stdint.h>

# ifdef USE_L4
#  include <l4/ipc.h>
# endif

struct hurd_message_buffer;

struct activation_frame
{
  /* **** ia32-exception-entry.S silently depends on the layout of
     this structure up to and including the next field ****  */
#ifdef i386
  union
  {
    uintptr_t regs[10];
    struct
    {
#define AF_REGS_FMT					\
      "ip: %p, sp: %p, eax: %p, ebx: %p, ecx: %p, "	\
      "edx: %p, edi: %p, esi: %p, ebp: %p, eflags: %p"
#define AF_REGS_PRINTF(activation_frame)		\
      (void *) activation_frame->eip,			\
      (void *) activation_frame->esp,			\
      (void *) activation_frame->eax,			\
      (void *) activation_frame->ebx,			\
      (void *) activation_frame->ecx,			\
      (void *) activation_frame->edx,			\
      (void *) activation_frame->edi,			\
      (void *) activation_frame->esi,			\
      (void *) activation_frame->ebp,			\
      (void *) activation_frame->eflags

      uintptr_t eax;
      uintptr_t ecx;
      uintptr_t edx;
      uintptr_t eflags;
      uintptr_t eip;
      uintptr_t ebx;
      uintptr_t edi;
      uintptr_t esi;
      uintptr_t ebp;
      uintptr_t esp;
    };
  };
#else
# error Not ported to this architecture!
#endif
  /* The base of the stack to use when running
     hurd_activation_handler_normal.  If NULL, then the interrupted
     stack is used.  */
  void *normal_mode_stack;

  struct activation_frame *next;
  struct activation_frame *prev;

  struct hurd_message_buffer *message_buffer;

#ifdef USE_L4
  /* We need to save parts of the UTCB.  */
  l4_word_t saved_sender;
  l4_word_t saved_receiver;
  l4_word_t saved_timeout;
  l4_word_t saved_error_code;
  l4_word_t saved_flags;
  l4_word_t saved_br0;
  l4_msg_t saved_message;
#endif

#define ACTIVATION_FRAME_CANARY 0x10ADAB1E
  uintptr_t canary;
};
#endif

#if defined (__need_activation_frame)
# undef __need_activation_frame
#else

#ifndef _HURD_THREAD_H
#define _HURD_THREAD_H 1

#include <viengoos/thread.h>

#include <stdint.h>
#include <hurd/types.h>
#include <viengoos/addr.h>
#include <viengoos/addr-trans.h>
#include <viengoos/cap.h>
#include <viengoos/messenger.h>
#include <setjmp.h>

/* The user thread control block.  */
struct hurd_utcb
{
  struct vg_utcb vg;

  /* Top of the activation frame stack (i.e., the active
     activation).  */
  struct activation_frame *activation_stack;
  /* The bottom of the activation stack.  */
  struct activation_frame *activation_stack_bottom;

  /* The CRC protects the above fields by checking for
     modification, which can happen if a call back function uses
     too much stack.  The fields following crc are not protected
     by the crc as they are expected to be changed by the
     activation handler.  */

  uintptr_t crc;

  /* The exception buffer.  */
  struct hurd_message_buffer *exception_buffer;
  /* The current extant IPC.  */
  struct hurd_message_buffer *extant_message;

  struct hurd_fault_catcher *catchers;

  /* The alternate activation stack.  */
  void *alternate_stack;
  bool alternate_stack_inuse;

  vg_thread_id_t tid;

#define UTCB_CANARY0 0xCA17A1
#define UTCB_CANARY1 0xDEADB15D
  uintptr_t canary0;
  uintptr_t canary1;
};

/* Return the calling thread's UTCB.  Threading libraries should set
   this to their own implementation once they are up and running.  */
extern struct hurd_utcb *(*hurd_utcb) (void);

/* Initializes the activation handler to allow receiving IPCs (but
   does not handle other faults).  This must be called exactly once
   before any IPCs are sent.  */
extern void hurd_activation_handler_init_early (void);

/* Initialize the activation handler.  This must be called after the
   storage sub-system has been initialized.  At this point, the
   activation handler is able to handle exceptions.  */
extern void hurd_activation_handler_init (void);


/* Allocate a utcb buffer and associated data structures (including an
   exception messenger) for the thread THEAD (which must already exist
   but should not be running).  Installs the UTCB and exception
   messenger in the thread object.  Returns the new UTCB in *UTCB.
   Returns 0 on success, otherwise an error code.  */
extern error_t hurd_activation_state_alloc (vg_addr_t thread,
					    struct hurd_utcb **utcb);

/* Release the state allocated by hurd_activation_state_alloc.  May
   not be called by a thread on its own UTCB!  */
extern void hurd_activation_state_free (struct hurd_utcb *utcb);


/* When a thread causes an activation, the kernel invokes the thread's
   activation handler.  This points to the low-level activation handler,
   which invokes activation_handler_activated.  (It is passed a pointer
   to the utcb.)

   This function must determine how to continue.  It may, but need
   not, immediately handle the activation.  The problem with handling
   an activation immediately is that this function runs on the
   activation handler's tiny stack and it runs in activated mode.  The
   latter means that it may not fault (which generally precludes
   accessing any dynamically allocated storage) or even properly send
   IPC (as it has no easy way to determine when the IPC has been
   received and when a reply is available--this information is
   delivered by activations!). 

   To allow an easy transition to another function in normal-mode, if
   the function returns an activation_frame, then the activation
   handler will call hurd_activation_handler_normal passing it that
   argument.  This function runs in normal mode and on the normal
   stack.  When this function returns, the interrupted state is
   restored.  */
extern struct activation_frame *hurd_activation_handler_activated
  (struct hurd_utcb *utcb);

extern void hurd_activation_handler_normal
  (struct activation_frame *activation_frame, struct hurd_utcb *utcb);


/* The first instruction of activation handler dispatcher.  */
extern char hurd_activation_handler_entry;
/* The instruction immediately following the last instruction of the
   activation handler dispatcher.  */
extern char hurd_activation_handler_end;


/* Register the current extant IPC.  */
extern void hurd_activation_message_register (struct hurd_message_buffer *mb);

/* Unregister the current extant IPC.  This is normally done
   automatically when a reply is receive.  However, if the IPC is
   aborted, then this function must be called before the next IPC may
   be sent.  */
extern void hurd_activation_message_unregister (struct hurd_message_buffer *mb);


/* Cause the activation frame to assume the state of the long jump
   buffer BUF.  If SET_RET is true, the normal function return value
   is set to RET.  */
extern void hurd_activation_frame_longjmp (struct activation_frame *af,
					   jmp_buf buf,
					   bool set_ret, int ret);


/* Dump the activation stack to stdout.  */
extern void hurd_activation_stack_dump (void);

struct hurd_fault_catcher
{
#define HURD_FAULT_CATCHER_MAGIC 0xb01dface
  uintptr_t magic;

  /* Start of the region to watch.  */
  uintptr_t start;
  /* Length of the region in bytes.  */
  uintptr_t len;
  /* The callback.  Return true to continue execute.  False to throw a
     SIGSEGV.  */
  bool (*callback) (struct activation_frame *activation_frame,
		    uintptr_t fault);

  struct hurd_fault_catcher *next;
  struct hurd_fault_catcher **prevp;
};

/* Register a fatch catch handler.  */
extern void hurd_fault_catcher_register (struct hurd_fault_catcher *catcher);

/* Unregister a fault catch handler.  */
extern void hurd_fault_catcher_unregister (struct hurd_fault_catcher *catcher);

static inline vg_thread_id_t
hurd_myself (void)
{
#ifdef USE_L4
  /* XXX: Annoyingly, we need the tid before UTCB->TID is initialized.
     This needs to be fixed, but for now...  */
  return l4_myself ();
#endif
  struct hurd_utcb *utcb = hurd_utcb ();

  assert (utcb);
  assert (utcb->tid);

  return utcb->tid;
}

#endif /* _HURD_THREAD_H */
#endif /* __need_activation_frame */