Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/vm/addrspace.c
2093 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <types.h>
31
#include <kern/errno.h>
32
#include <lib.h>
33
#include <addrspace.h>
34
#include <proc.h>
35
#include <vm.h>
36
#include <vm/region.h>
37
#include <vm/page.h>
38
#include <vm/swap.h>
39
#include <array.h>
40
#include <cpu.h>
41
#include <machine/coremap.h>
42
#include <machine/tlb.h>
43
#include <current.h>
44
45
/*
46
* Note! If OPT_DUMBVM is set, as is the case until you start the VM
47
* assignment, this file is not compiled or linked or in any way
48
* used. The cheesy hack versions in dumbvm.c are used instead.
49
*/
50
51
DEFARRAY_BYTYPE( vm_region_array ,struct vm_region, /* ... */);
52
53
struct addrspace *
54
as_create(void)
55
{
56
struct addrspace *as;
57
58
as = kmalloc(sizeof(struct addrspace));
59
if (as == NULL) {
60
return NULL;
61
}
62
63
//create the array of regions.
64
as->as_regions = vm_region_array_create();
65
if( as->as_regions == NULL ) {
66
kfree( as );
67
return NULL;
68
}
69
70
//set the heap start.
71
as->as_heap_start = 0;
72
as->as_heap_end = 0;
73
74
return as;
75
}
76
77
int
78
as_copy(struct addrspace *old, struct addrspace **ret)
79
{
80
struct addrspace *newas;
81
struct vm_region *vmr;
82
struct vm_region *newvmr;
83
unsigned i;
84
int result;
85
86
newas = as_create();
87
if (newas==NULL) {
88
return ENOMEM;
89
}
90
91
//copy all vm regions that reside in the old addrspace.
92
for( i = 0; i < vm_region_array_num( old->as_regions ); ++i ) {
93
vmr = vm_region_array_get( old->as_regions, i );
94
95
//if clone fails, we simply return the reason
96
//it failed, after destroying newas.
97
result = vm_region_clone( vmr, &newvmr );
98
if( result ) {
99
as_destroy( newas );
100
return result;
101
}
102
103
result = vm_region_array_add( newas->as_regions, newvmr, NULL );
104
if( result ) {
105
vm_region_destroy( newvmr );
106
as_destroy( newas );
107
return result;
108
}
109
}
110
111
*ret = newas;
112
return 0;
113
}
114
115
void
116
as_destroy(struct addrspace *as)
117
{
118
struct vm_region *vmr;
119
unsigned i;
120
121
//destroy each vm region associated with this addrspace.
122
for( i = 0; i < vm_region_array_num( as->as_regions ); ++i ) {
123
vmr = vm_region_array_get( as->as_regions, i );
124
vm_region_destroy( vmr );
125
}
126
127
//reside the regions array to 0, and
128
//destroy the array.
129
vm_region_array_setsize( as->as_regions, 0 );
130
vm_region_array_destroy( as->as_regions );
131
132
kfree( as );
133
}
134
135
void
136
as_activate(struct addrspace *as)
137
{
138
KASSERT( as != NULL || curthread->t_addrspace == as );
139
//if the given addrspace is different the one we may have tlb entries for
140
if( as != curcpu->c_lastas ) {
141
LOCK_COREMAP();
142
//set the given addrspace to be the last one
143
curcpu->c_lastas = as;
144
//clear the tlb entry.
145
tlb_clear();
146
147
UNLOCK_COREMAP();
148
}
149
}
150
151
static
152
bool
153
as_overlaps_region( struct addrspace *as, size_t sz, vaddr_t vaddr ) {
154
unsigned i;
155
vaddr_t bottom;
156
vaddr_t top;
157
struct vm_region *vmr;
158
159
//loop over all regions.
160
for( i = 0; i < vm_region_array_num( as->as_regions ); ++i ) {
161
//get the current region.
162
vmr = vm_region_array_get( as->as_regions, i );
163
164
//calculate bottom and top virtual addresses.
165
bottom = vmr->vmr_base;
166
top = bottom + vm_page_array_num( vmr->vmr_pages ) * PAGE_SIZE;
167
168
//if the tail & head of the new vm_region are inside
169
//the current address space block,then we have an overlap.
170
if( vaddr + sz > bottom && vaddr < top )
171
return true;
172
}
173
174
return false;
175
}
176
/*
177
* Set up a segment at virtual address VADDR of size MEMSIZE. The
178
* segment in memory extends from VADDR up to (but not including)
179
* VADDR+MEMSIZE.
180
*
181
* The READABLE, WRITEABLE, and EXECUTABLE flags are set if read,
182
* write, or execute permission should be set on the segment. At the
183
* moment, these are ignored. When you write the VM system, you may
184
* want to implement them.
185
*/
186
int
187
as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
188
int readable, int writeable, int executable)
189
{
190
struct vm_region *vmr;
191
int res;
192
193
(void) readable;
194
(void) writeable;
195
(void) executable;
196
197
//align the virtual address.
198
vaddr &= PAGE_FRAME;
199
200
//round up the size so it is a multiple of the page size.
201
sz = ROUNDUP(sz, PAGE_SIZE);
202
203
//if there's an overlap, well we have a problem.
204
if( as_overlaps_region( as, sz, vaddr ) )
205
return EINVAL;
206
207
//create a region with the specified amount of pages.
208
vmr = vm_region_create( sz / PAGE_SIZE );
209
if( vmr == NULL )
210
return ENOMEM;
211
212
vmr->vmr_base = vaddr;
213
//add it to the addresspace.
214
res = vm_region_array_add( as->as_regions, vmr, NULL );
215
if( res ) {
216
vm_region_destroy( vmr );
217
return res;
218
}
219
220
//if the new vaddr is larger then heap_size ..
221
if( vmr->vmr_base > as->as_heap_start && vaddr != USERSTACKBASE )
222
as->as_heap_start = vmr->vmr_base + sz;
223
224
return 0;
225
}
226
227
int
228
as_prepare_load(struct addrspace *as)
229
{
230
return as_define_region(
231
as, as->as_heap_start, 0, 1, 1, 0
232
);
233
}
234
235
int
236
as_complete_load(struct addrspace *as)
237
{
238
(void)as;
239
return 0;
240
}
241
242
int
243
as_define_stack(struct addrspace *as, vaddr_t *stackptr)
244
{
245
int err;
246
247
//create the stack region.
248
err = as_define_region( as, USERSTACKBASE, USERSTACKSIZE, 1, 1, 0 );
249
if( err )
250
return err;
251
252
*stackptr = USERSTACK;
253
return 0;
254
}
255
256
int
257
as_fault( struct addrspace *as, int fault_type, vaddr_t fault_addr ) {
258
struct vm_region *vmr;
259
int ix_page;
260
struct vm_page *vmp;
261
int res;
262
263
KASSERT( as != NULL );
264
265
//find the responsible vm_region for the faulty address.
266
vmr = vm_region_find_responsible( as, fault_addr );
267
if( vmr == NULL )
268
return EFAULT;
269
270
//find the responsible vm_page.
271
ix_page = (fault_addr - vmr->vmr_base) / PAGE_SIZE;
272
273
//get the virtual page.
274
vmp = vm_page_array_get( vmr->vmr_pages, ix_page );
275
276
//if the virtual page is null, it means we have to zero-fill it.
277
if( vmp == NULL ) {
278
//create a new blank page
279
res = vm_page_new_blank( &vmp );
280
if( res )
281
return res;
282
283
//append to to the region.
284
vm_page_array_set( vmr->vmr_pages, ix_page, vmp );
285
}
286
return vm_page_fault( vmp, as, fault_type, fault_addr );
287
}
288
289