summaryrefslogtreecommitdiff
path: root/hurd/exceptions.h
blob: c1d196076c0671be0736898c049e148f6efffb45 (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
/* exceptions.h - Exception handling definitions.
   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   This file is part of the GNU Hurd.

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

   The 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 the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#ifndef _HURD_EXCEPTIONS_H
#define _HURD_EXCEPTIONS_H 1

#include <hurd/stddef.h>

#ifndef ASM

#include <stdint.h>
#include <hurd/cap.h>
#include <hurd/thread.h>
#include <l4/thread.h>
#include <hurd/error.h>

#define RPC_STUB_PREFIX exception
#define RPC_ID_PREFIX EXCEPTION
#define RPC_TARGET_NEED_ARG
#define RPC_TARGET_ARG_TYPE l4_thread_id_t
#define RPC_TARGET(x) (x)
#include <hurd/rpc.h>

/* Exception message ids.  */
enum
  {
    EXCEPTION_fault = 10,
  };

/* Return a string corresponding to a message id.  */
static inline const char *
exception_method_id_string (l4_word_t id)
{
  switch (id)
    {
    case EXCEPTION_fault:
      return "fault";
    default:
      return "unknown";
    }
}

struct exception_info
{
  union
  {
    struct
    {
      /* Type of access.  */
      uintptr_t access: 3;
      /* Type of object that was attempting to be accessed.  */
      uintptr_t type : CAP_TYPE_BITS;
      /* Whether the page was discarded.  */
      uintptr_t discarded : 1;
    };
    uintptr_t raw;
  };
};

#define EXCEPTION_INFO_FMT "%c%c%c %s %s"
#define EXCEPTION_INFO_PRINTF(info)			\
  ((info).access & L4_FPAGE_READABLE ? 'r' : '~'),	\
    ((info).access & L4_FPAGE_WRITABLE ? 'w' : '~'),	\
    ((info).access & L4_FPAGE_EXECUTABLE ? 'r' : '~'),	\
    cap_type_string ((info).type),			\
    (info.discarded) ? "discarded" : ""

/* Raise a fault at address FAULT_ADDRESS.  If IP is not 0, then IP is
   the value of the IP of the faulting thread at the time of the fault
   and SP the value of the stack pointer at the time of the fault.  */
RPC (fault, 4, 0, addr_t, fault_address, uintptr_t, sp, uintptr_t, ip,
     struct exception_info, exception_info)

#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
#undef RPC_TARGET_NEED_ARG
#undef RPC_TARGET_ARG_TYPE
#undef RPC_TARGET

#define RPC_STUB_PREFIX rm
#define RPC_ID_PREFIX RM
#undef RPC_TARGET_NEED_ARG
#define RPC_TARGET \
  ({ \
    extern struct hurd_startup_data *__hurd_startup_data; \
    __hurd_startup_data->rm; \
  })

#include <hurd/rpc.h>

/* Exception message ids.  */
enum
  {
    RM_exception_collect = 500,
  };

/* Cause the delivery of a pending event, if any.  */
RPC(exception_collect, 1, 0, addr_t, principal)

#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
#undef RPC_TARGET
#endif /* !ASM  */

/* The exception stack is 4 pages large.  The word beyond the base of
   the stack is a pointer to the exception page, which is usually the
   last page of the stack.  */
#define EXCEPTION_STACK_SIZE_LOG2 (PAGESIZE_LOG2 + 2)
#define EXCEPTION_STACK_SIZE (1 << EXCEPTION_STACK_SIZE_LOG2)

#ifndef ASM

/* Initialize the exception handler.  */
extern void exception_handler_init (void);


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

   This function must determine how to continue.  It may, but need
   not, immediately handle the fault.  The problem with handling the
   fault immediately is that this function runs on the exception
   handler's tiny stack (~3kb) and it runs in activated mode.  The
   latter means that it may not fault (which generally precludes
   accessing any dynamically allocated storage).  To allow an easy
   transition to another function in normal-mode, if the function
   returns an exception_frame, then the exception handler will call
   exception_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 exception_frame *
  exception_handler_activated (struct exception_page *exception_page);

extern void exception_handler_normal (struct exception_frame *exception_frame);

/* Should be called before destroyed the exception page associated
   with a thread.  */
extern void exception_page_cleanup (struct exception_page *exception_page);

/* The first instruction of exception handler dispatcher.  */
extern char exception_handler_entry;
/* The instruction immediately following the last instruction of the
   exception handler dispatcher.  */
extern char exception_handler_end;

#endif /* !ASM */

#endif