1 |
/* physmem.h - Generic definitions. |
/* physmem.c - Generic definitions. |
2 |
Copyright (C) 2003 Free Software Foundation, Inc. |
Copyright (C) 2003, 2005 Free Software Foundation, Inc. |
3 |
Written by Marcus Brinkmann. |
Written by Neal H. Walfield <neal@gnu.org>. |
4 |
|
|
5 |
This file is part of the GNU Hurd. |
This file is part of the GNU Hurd. |
6 |
|
|
8 |
modify it under the terms of the GNU General Public License as |
modify it under the terms of the GNU General Public License as |
9 |
published by the Free Software Foundation; either version 2, or (at |
published by the Free Software Foundation; either version 2, or (at |
10 |
your option) any later version. |
your option) any later version. |
11 |
|
|
12 |
The GNU Hurd is distributed in the hope that it will be useful, but |
The GNU Hurd is distributed in the hope that it will be useful, but |
13 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 |
General Public License for more details. |
General Public License for more details. |
16 |
|
|
17 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
18 |
along with this program; if not, write to the Free Software |
along with the GNU Hurd; see the file COPYING. If not, write to |
19 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ |
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, |
20 |
|
USA. */ |
21 |
|
|
22 |
#include <errno.h> |
#include <errno.h> |
|
|
|
23 |
#include <l4.h> |
#include <l4.h> |
24 |
|
#include <hurd/btree.h> |
25 |
#include <hurd/cap-server.h> |
#include <hurd/cap-server.h> |
26 |
|
|
27 |
#include "string.h" |
#include <compiler.h> |
28 |
|
|
29 |
#include "output.h" |
#include "output.h" |
30 |
|
|
31 |
|
|
45 |
void switch_thread (l4_thread_id_t from, l4_thread_id_t to); |
void switch_thread (l4_thread_id_t from, l4_thread_id_t to); |
46 |
|
|
47 |
|
|
48 |
/* Container objects. */ |
/* Return true if INDEX lies within (START, START+SIZE-1) |
49 |
|
inclusive. */ |
50 |
|
static bool |
51 |
|
within (l4_word_t index, l4_word_t start, l4_word_t size) |
52 |
|
{ |
53 |
|
return index >= start && index < start + size; |
54 |
|
} |
55 |
|
|
56 |
struct container |
/* Return true if (INDEX1, INDEX1+SIZE1-1) inclusive overlaps with |
57 |
|
(INDEX2, INDEX2+SIZE2-1) inclusive. */ |
58 |
|
static bool |
59 |
|
overlap (l4_word_t index1, l4_word_t size1, l4_word_t index2, l4_word_t size2) |
60 |
|
{ |
61 |
|
return |
62 |
|
/* Is the start of the first region within the second? |
63 |
|
2 1 2 1 |
64 |
|
or 2 1 1 2 */ |
65 |
|
within (index1, index2, size2) |
66 |
|
/* Is the end of the first region within the second? |
67 |
|
1 2 1 2 |
68 |
|
or 2 1 1 2 */ |
69 |
|
|| within (index1 + size1 - 1, index2, size2) |
70 |
|
/* Is start of the second region within the first? |
71 |
|
1 2 1 2 |
72 |
|
or 1 2 2 1 */ |
73 |
|
|| within (index2, index1, size1); |
74 |
|
|
75 |
|
/* We have implicitly checked if the end of the second region is |
76 |
|
within the first (i.e. within (index2 + size2 - 1, index1, size1)) |
77 |
|
2 1 2 1 |
78 |
|
or 1 2 2 1 |
79 |
|
in check 1 and check 3. */ |
80 |
|
} |
81 |
|
|
82 |
|
/* A region of memory. */ |
83 |
|
struct region |
84 |
|
{ |
85 |
|
/* Start of the region. */ |
86 |
|
uintptr_t start; |
87 |
|
/* And its extent. */ |
88 |
|
size_t size; |
89 |
|
}; |
90 |
|
|
91 |
|
static inline int |
92 |
|
region_compare (const struct region *a, const struct region *b) |
93 |
|
{ |
94 |
|
if (overlap (a->start, a->size, b->start, b->size)) |
95 |
|
return 0; |
96 |
|
else |
97 |
|
return a->start - b->start; |
98 |
|
} |
99 |
|
|
100 |
|
/* Forward. */ |
101 |
|
struct frame_entry; |
102 |
|
|
103 |
|
/* A frame referrs directly to physical memory. Any allocated memory |
104 |
|
(for users) will have exactly one frame structure referring to |
105 |
|
it. */ |
106 |
|
struct frame |
107 |
{ |
{ |
108 |
/* For now, a container is nothing more than a contiguous, |
/* One reference per frame entry plus any active users. */ |
109 |
page-aligned range of memory. This is the reason why |
int refs; |
|
L4_FPAGE_SPAN_MAX fpages are sufficient. */ |
|
|
l4_fpage_t fpages[L4_FPAGE_SPAN_MAX]; |
|
110 |
|
|
111 |
/* The number of entries in FPAGES. */ |
/* The physical memory allocated to this frame. This is allocated |
112 |
l4_word_t nr_fpages; |
lazily. If this address portion is NULL, no memory has yet been |
113 |
|
allocated. */ |
114 |
|
l4_fpage_t memory; |
115 |
|
|
116 |
|
/* If a mapping has been made since the last time this frame was |
117 |
|
unmapped. This does not mean that it actually is mapped as any |
118 |
|
users could have unmapped it themselves. */ |
119 |
|
bool may_be_mapped; |
120 |
|
|
121 |
|
/* List of frame entries referring to this frame. */ |
122 |
|
struct frame_entry *frame_entries; |
123 |
}; |
}; |
|
typedef struct container *container_t; |
|
124 |
|
|
125 |
|
/* Regions in containers refer to physical memory. Multiple regions |
126 |
|
may refer to the same phsyical memory (thereby allowing sharing and |
127 |
|
COW). Every region has its own frame entry which contains the |
128 |
|
per-region state. FRAME refers to the physical memory. */ |
129 |
|
struct frame_entry |
130 |
|
{ |
131 |
|
/* The name of this region within the containing container. */ |
132 |
|
struct region region; |
133 |
|
/* The physical memory backing the region. */ |
134 |
|
struct frame *frame; |
135 |
|
/* The frame entry may not reference all of the physical memory in |
136 |
|
FRAME (due to partial sharing, etc). This offset to the start of |
137 |
|
the memory which this frame entry uses. */ |
138 |
|
size_t frame_offset; |
139 |
|
|
140 |
|
hurd_btree_node_t node; |
141 |
|
|
142 |
|
/* The list entry for FRAME's list of frame entries referring to |
143 |
|
itself. */ |
144 |
|
struct frame_entry *next; |
145 |
|
struct frame_entry **prevp; |
146 |
|
}; |
147 |
|
|
148 |
/* Initialize the container class subsystem. */ |
BTREE_CLASS(frame_entry, struct frame_entry, struct region, region, |
149 |
error_t container_class_init (); |
node, region_compare) |
150 |
|
|
151 |
|
struct container |
152 |
|
{ |
153 |
|
pthread_mutex_t lock; |
154 |
|
/* List of allocate frames in this container. */ |
155 |
|
hurd_btree_frame_entry_t frame_entries; |
156 |
|
}; |
157 |
|
|
158 |
|
/* Allocate an uninitialized frame entry structure. Returns NULL if |
159 |
|
there is insufficient memory. */ |
160 |
|
extern struct frame_entry *frame_entry_alloc (void); |
161 |
|
|
162 |
|
/* Deallocate frame entry FRAME_ENTRY. NB: this function does not |
163 |
|
deinitialize any resources FRAME_ENTRY may still reference. It is |
164 |
|
the dual of frame_entry_alloc. */ |
165 |
|
extern void frame_entry_dealloc (struct frame_entry *frame_entry); |
166 |
|
|
167 |
|
/* Initialize the previously unitialized frame entry structure, |
168 |
|
FRAME_ENTRY to cover the region starting at byte START and |
169 |
|
extending SIZE bytes on container CONT. SIZE must be a power of 2. |
170 |
|
CONT must be locked. Physical memory is reserved, however, it is |
171 |
|
not allocated until a frame is attached and that frame is bound |
172 |
|
using frame_memory_bind. |
173 |
|
|
174 |
|
If the specified region overlaps with any in the container, EEXIST |
175 |
|
is returned. */ |
176 |
|
extern error_t frame_entry_new (struct container *cont, |
177 |
|
struct frame_entry *frame_entry, |
178 |
|
uintptr_t start, size_t size); |
179 |
|
|
180 |
|
/* Initialize the previously uninitialized frame entry structure |
181 |
|
FRAME_ENTRY to cover the region starting at byte START and |
182 |
|
extending SIZE bytes on container CONT. If FRAME is non-NULL, |
183 |
|
FRAME_ENTRY refers to the physical memory in FRAME starting at |
184 |
|
offset OFFSET (hence when OFFSET is non-zero, FRAME_ENTRY only |
185 |
|
refers to a portion of FRAME). SIZE must be a power of 2. CONT |
186 |
|
must be locked. A reference is added to FRAME. |
187 |
|
|
188 |
|
If the specified region overlaps with any in the container, EEXIST |
189 |
|
is returned. */ |
190 |
|
extern error_t frame_entry_use (struct container *cont, |
191 |
|
struct frame_entry *frame_entry, |
192 |
|
uintptr_t start, size_t size, |
193 |
|
struct frame *frame, |
194 |
|
size_t offset); |
195 |
|
|
196 |
|
/* Deinitialize frame entry FRAME_ENTRY which is in the locked |
197 |
|
container CONT dereferencing any frame it may be using in the |
198 |
|
process. This does *not* deallocate the FRAME_ENTRY structure. |
199 |
|
This must still be done using frame_entry_dealloc. */ |
200 |
|
extern void frame_entry_drop (struct container *cont, |
201 |
|
struct frame_entry *frame_entry); |
202 |
|
|
203 |
|
/* Find a frame entry which overlaps with the region START+SIZE and |
204 |
|
return it. Returns NULL if no frame entry in container overlaps |
205 |
|
with the provided region. CONT must be locked. */ |
206 |
|
extern struct frame_entry *frame_entry_find (struct container *cont, |
207 |
|
uintptr_t start, |
208 |
|
size_t size); |
209 |
|
|
210 |
|
/* Attach frame entry FRAME_ENTRY into container CONT. FRAME_ENTRY |
211 |
|
must not currently be part of any container. Returns EEXIST if |
212 |
|
FRAME_ENTRY overlaps with a frame entry in CONT. */ |
213 |
|
extern error_t frame_entry_attach (struct container *cont, |
214 |
|
struct frame_entry *frame_entry); |
215 |
|
|
216 |
|
/* Detach frame entry FRAME_ENTRY from container CONT. */ |
217 |
|
extern void frame_entry_detach (struct container *cont, |
218 |
|
struct frame_entry *frame_entry); |
219 |
|
|
220 |
|
/* Allocate a frame structure holding SIZE bytes. Physical memory |
221 |
|
must have already been reserved (by, e.g. a prior frame_entry_alloc |
222 |
|
call). Allocation of the physical memory is deferred until |
223 |
|
frame_memory_alloc is called. The returned frame has a single |
224 |
|
reference and is locked. */ |
225 |
|
extern struct frame *frame_alloc (size_t size); |
226 |
|
|
227 |
|
/* Bind frame FRAME to physical memory if not already done. */ |
228 |
|
static inline void |
229 |
|
frame_memory_bind (struct frame *frame) |
230 |
|
{ |
231 |
|
/* Actually allocates the physical memory. */ |
232 |
|
extern void frame_memory_alloc (struct frame *frame); |
233 |
|
|
234 |
|
if (! l4_address (frame->memory)) |
235 |
|
frame_memory_alloc (frame); |
236 |
|
} |
237 |
|
|
238 |
|
/* Add a reference to frame FRAME. */ |
239 |
|
static inline void |
240 |
|
frame_ref (struct frame *frame) |
241 |
|
{ |
242 |
|
frame->refs ++; |
243 |
|
} |
244 |
|
|
245 |
|
/* Release a reference to frame FRAME. FRAME must be locked. When |
246 |
|
the last reference is removed, any exant client mappings will be |
247 |
|
unmapped, any physical memory will be deallocated and FRAME will be |
248 |
|
freed. */ |
249 |
|
extern void frame_deref (struct frame *frame); |
250 |
|
|
251 |
|
/* Add FRAME_ENTRY as a user of FRAME. A reference for FRAME_ENTRY |
252 |
|
must already be held. */ |
253 |
|
extern void frame_use (struct frame *frame, |
254 |
|
struct frame_entry *frame_entry); |
255 |
|
|
256 |
|
/* Remove FRAME_ENTRY as a user of FRAME. A reference to frame is |
257 |
|
released in the process. */ |
258 |
|
extern void frame_drop (struct frame *frame, |
259 |
|
struct frame_entry *frame_entry); |
260 |
|
|
261 |
/* Allocate a new container object covering the NR_FPAGES fpages |
/* Allocate a new container object covering the NR_FPAGES fpages |
262 |
listed in FPAGES. The object returned is locked and has one |
listed in FPAGES. The object returned is locked and has one |
263 |
reference. */ |
reference. */ |
264 |
error_t container_alloc (l4_word_t nr_fpages, l4_word_t *fpages, |
extern error_t container_alloc (l4_word_t nr_fpages, l4_word_t *fpages, |
265 |
container_t *r_container); |
struct container **r_container); |
266 |
|
|