Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/vm/vmregion.c
2093 views
1
#include <types.h>
2
#include <kern/errno.h>
3
#include <lib.h>
4
#include <array.h>
5
#include <addrspace.h>
6
#include <vm.h>
7
#include <vm/region.h>
8
#include <vm/swap.h>
9
#include <vm/page.h>
10
#include <machine/coremap.h>
11
12
DEFARRAY_BYTYPE( vm_page_array, struct vm_page, /* no inline */ );
13
14
struct vm_region *
15
vm_region_create( size_t npages ) {
16
int res;
17
struct vm_region *vmr;
18
unsigned i;
19
int err;
20
21
//see if we can reserve npages of swap first.
22
err = swap_reserve( npages );
23
if( err )
24
return NULL;
25
26
//attempt to create the vm_region
27
vmr = kmalloc( sizeof( struct vm_region ) );
28
if( vmr == NULL )
29
return NULL;
30
31
//create the vm_pages.
32
vmr->vmr_pages = vm_page_array_create();
33
if( vmr->vmr_pages == NULL ) {
34
kfree( vmr );
35
swap_unreserve( npages );
36
return NULL;
37
}
38
39
//set the base address to point to an invalid virtual address.
40
vmr->vmr_base = 0xdeadbeef;
41
42
//adjust the array to hold npages.
43
res = vm_page_array_setsize( vmr->vmr_pages, npages );
44
if( res ) {
45
vm_page_array_destroy( vmr->vmr_pages );
46
kfree( vmr );
47
swap_unreserve( npages );
48
return NULL;
49
}
50
51
//initialize all the pages to NULL.
52
for( i = 0; i < npages; ++i )
53
vm_page_array_set( vmr->vmr_pages, i, NULL );
54
55
return vmr;
56
}
57
58
void
59
vm_region_destroy( struct vm_region *vmr ) {
60
//resize the vm region to 0.
61
KASSERT( vm_region_resize( vmr, 0 ) == 0 );
62
63
//destroy the pages associated with the region.
64
vm_page_array_destroy( vmr->vmr_pages );
65
66
//free the memory
67
kfree( vmr );
68
}
69
70
static
71
int
72
vm_region_shrink( struct vm_region *vmr, unsigned npages ) {
73
unsigned i;
74
struct vm_page *vmp;
75
76
for( i = npages; i < vm_page_array_num( vmr->vmr_pages ); ++i ) {
77
vmp = vm_page_array_get( vmr->vmr_pages, i );
78
if( vmp == NULL ) {
79
swap_unreserve( 1 );
80
continue;
81
}
82
83
//unmap tlb entries.
84
vm_unmap( vmr->vmr_base + PAGE_SIZE * i );
85
86
//destroy the page.
87
vm_page_destroy( vmp );
88
}
89
90
return vm_page_array_setsize( vmr->vmr_pages, npages );
91
}
92
93
static
94
int
95
vm_region_expand( struct vm_region *vmr, unsigned npages ) {
96
unsigned new_pages;
97
int res;
98
unsigned i;
99
unsigned old_pages;
100
101
old_pages = vm_page_array_num( vmr->vmr_pages );
102
new_pages = npages - old_pages;
103
104
//trivial case, nothing to do.
105
if( new_pages == 0 )
106
return 0;
107
108
//see if we can back this loan with storage.
109
res = swap_reserve( new_pages );
110
if( res )
111
return res;
112
113
//attempt to rezize the vmr_pages array.
114
res = vm_page_array_setsize( vmr->vmr_pages, npages );
115
if( res ) {
116
swap_unreserve( new_pages );
117
return res;
118
}
119
120
121
//initialize each of the newly created vm_pages to NULL.
122
for( i = old_pages; i < npages; ++i )
123
vm_page_array_set( vmr->vmr_pages, i, NULL );
124
125
return 0;
126
}
127
128
int
129
vm_region_resize( struct vm_region *vmr, unsigned npages ) {
130
KASSERT( vmr != NULL );
131
KASSERT( vmr->vmr_pages != NULL );
132
133
if( npages < vm_page_array_num( vmr->vmr_pages ) )
134
return vm_region_shrink( vmr, npages );
135
return vm_region_expand( vmr, npages );
136
}
137
138
int
139
vm_region_clone( struct vm_region *source, struct vm_region **target ) {
140
struct vm_region *vmr;
141
unsigned i;
142
struct vm_page *vmp;
143
struct vm_page *vmp_clone;
144
int res;
145
146
//create a new vm_region with the same amount of pages
147
//as the previous one.
148
vmr = vm_region_create( vm_page_array_num( source->vmr_pages ) );
149
if( vmr == NULL )
150
return ENOMEM;
151
152
//copy the base.
153
vmr->vmr_base = source->vmr_base;
154
155
//loop over each of the pages
156
for( i = 0; i < vm_page_array_num( source->vmr_pages ); ++i ) {
157
vmp = vm_page_array_get( source->vmr_pages, i );
158
vmp_clone = vm_page_array_get( vmr->vmr_pages, i );
159
160
//if the page from the old addrspace is null, we dont
161
//have anything to do.
162
if( vmp == NULL )
163
continue;
164
165
//clone the page.
166
res = vm_page_clone( vmp, &vmp_clone );
167
if( res ) {
168
vm_region_destroy( vmr );
169
return res;
170
}
171
172
//now that we have the cloned page, add it to
173
//the addrspace array
174
vm_page_array_set( vmr->vmr_pages, i, vmp_clone );
175
}
176
177
//copy to the given pointer
178
*target = vmr;
179
return 0;
180
}
181
182
struct vm_region *
183
vm_region_find_responsible( struct addrspace *as, vaddr_t vaddr ) {
184
unsigned ix;
185
struct vm_region *vmr;
186
vaddr_t top;
187
vaddr_t bottom;
188
189
//loop over all possible regions.
190
for( ix = 0; ix < vm_region_array_num( as->as_regions ); ++ix ) {
191
//get the vm_region
192
vmr = vm_region_array_get( as->as_regions, ix );
193
194
//calculate top and bottom
195
bottom = vmr->vmr_base;
196
top = vmr->vmr_base + vm_page_array_num( vmr->vmr_pages ) * PAGE_SIZE;
197
198
//if the virtual address is between bottom and top
199
//thats the vm_region we are looking for.
200
if( (vaddr >= bottom && vaddr < top) || ((vaddr == bottom) && (vaddr == top)))
201
return vmr;
202
}
203
return NULL;
204
}
205
206
207