annotate src/impl/vm_impl_private.cbc @ 281:4d76280758db

move context.pm to util.pm ...
author anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Tue, 28 Jan 2020 16:50:07 +0900
parents 052669f2ef74
children 9fa2e66bc9ed
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
226
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
1 #include "param.h"
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
2 #include "proc.h"
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
3 #include "mmu.h"
222
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
4 #include "defs.h"
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
5 #include "memlayout.h"
200
1301727600cc success build
anatofuz
parents:
diff changeset
6 #interface "vm_impl.h"
1301727600cc success build
anatofuz
parents:
diff changeset
7
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
8 /*
281
4d76280758db move context.pm to util.pm ...
anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp>
parents: 270
diff changeset
9 vm_impl* createvm_impl2(); //:skip
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
10 */
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
11
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
12 __code loaduvm_ptesize_checkvm_impl(struct vm_impl* vm_impl, __code next(int ret, ...)) {
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
13 char* addr = vm_impl->addr;
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
14
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
15 if ((uint) addr %PTE_SZ != 0) {
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
16 // goto panic
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
17 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
18
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
19 goto loaduvm_loopvm_impl(vm_impl, next(ret, ...));
200
1301727600cc success build
anatofuz
parents:
diff changeset
20 }
1301727600cc success build
anatofuz
parents:
diff changeset
21
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
22 __code loaduvm_loopvm_impl(struct vm_impl* vm_impl, __code next(int ret, ...)) {
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
23 uint i = vm_impl->i;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
24 uint sz = vm_impl->sz;
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
25
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
26 if (i < sz) {
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
27 goto loaduvm_check_pgdir(vm_impl, next(ret, ...));
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
28 }
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
29
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
30 goto loaduvm_exit(vm_impl, next(ret, ...));
200
1301727600cc success build
anatofuz
parents:
diff changeset
31 }
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
32
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
33
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
34 static pte_t* walkpgdir (pde_t *pgdir, const void *va, int alloc)
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
35 {
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
36 pde_t *pde;
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
37 pte_t *pgtab;
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
38
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
39 // pgdir points to the page directory, get the page direcotry entry (pde)
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
40 pde = &pgdir[PDE_IDX(va)];
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
41
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
42 if (*pde & PE_TYPES) {
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
43 pgtab = (pte_t*) p2v(PT_ADDR(*pde));
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
44
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
45 } else {
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
46 if (!alloc || (pgtab = (pte_t*) kpt_alloc()) == 0) {
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
47 return 0;
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
48 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
49
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
50 // Make sure all those PTE_P bits are zero.
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
51 memset(pgtab, 0, PT_SZ);
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
52
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
53 // The permissions here are overly generous, but they can
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
54 // be further restricted by the permissions in the page table
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
55 // entries, if necessary.
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
56 *pde = v2p(pgtab) | UPDE_TYPE;
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
57 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
58
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
59 return &pgtab[PTE_IDX(va)];
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
60 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
61
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
62
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
63 __code loaduvm_check_pgdir(struct vm_impl* vm_impl, __code next(int ret, ...)) {
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
64 pte_t* pte = vm_impl->pte;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
65 pde_t* pgdir = vm_impl->pgdir;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
66 uint i = vm_impl->i;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
67 char* addr = vm_impl->addr;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
68 uint pa = vm_impl->pa;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
69
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
70 if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) {
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
71 // goto panic
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
72 }
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
73 pa = PTE_ADDR(*pte);
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
74
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
75 vm_impl->pte = pte;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
76 vm_impl->pgdir = pgdir;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
77 vm_impl->addr = addr;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
78 vm_impl->pa = pa;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
79
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
80 goto loaduvm_check_PTE_SZ(vm_impl, next(ret, ...));
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
81 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
82
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
83 __code loaduvm_check_PTE_SZ(struct vm_impl* vm_impl, __code next(int ret, ...)) {
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
84 uint sz = vm_impl->sz;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
85 uint i = vm_impl->i;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
86 uint n = vm_impl->n;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
87 struct inode* ip = vm_impl->ip;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
88 uint pa = vm_impl->pa;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
89 uint offset = vm_impl->offset;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
90
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
91 if (sz - i < PTE_SZ) {
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
92 n = sz - i;
207
8a55878f6a25 loaduvm
tobaru
parents: 206
diff changeset
93 } else {
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
94 n = PTE_SZ;
207
8a55878f6a25 loaduvm
tobaru
parents: 206
diff changeset
95 }
8a55878f6a25 loaduvm
tobaru
parents: 206
diff changeset
96
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
97 if (readi(ip, p2v(pa), offset + i, n) != n) {
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
98 ret = -1;
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
99 goto next(ret, ...);
207
8a55878f6a25 loaduvm
tobaru
parents: 206
diff changeset
100 }
8a55878f6a25 loaduvm
tobaru
parents: 206
diff changeset
101
208
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
102 vm_impl->n = n;
a0620ca23f19 be functional loaduvm
tobaru
parents: 207
diff changeset
103
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
104 goto loaduvm_loopvm_impl(vm_impl, next(ret, ...));
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
105 }
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
106
219
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
107 __code loaduvm_exit(struct vm_impl* vm_impl, __code next(int ret, ...)) {
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
108 ret = 0;
b8597756f701 fix loaduvm loop
tobaru
parents: 218
diff changeset
109 goto next(ret, ...);
206
247aa9ee931c loaduvm_loopvm_impl
tobaru
parents: 205
diff changeset
110 }
211
66db83ec1ec2 kpt_alloc_check_impl and freerange
tobaru
parents: 208
diff changeset
111
212
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
112 struct run {
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
113 struct run *next;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
114 };
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
115
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
116 struct {
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
117 struct spinlock lock;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
118 struct run* freelist;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
119 } kpt_mem;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
120
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
121
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
122 static int mappages (pde_t *pgdir, void *va, uint size, uint pa, int ap)
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
123 {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
124 char *a, *last;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
125 pte_t *pte;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
126
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
127 a = (char*) align_dn(va, PTE_SZ);
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
128 last = (char*) align_dn((uint)va + size - 1, PTE_SZ);
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
129
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
130 for (;;) {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
131 if ((pte = walkpgdir(pgdir, a, 1)) == 0) {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
132 return -1;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
133 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
134
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
135 if (*pte & PE_TYPES) {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
136 panic("remap");
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
137 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
138
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
139 *pte = pa | ((ap & 0x3) << 4) | PE_CACHE | PE_BUF | PTE_TYPE;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
140
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
141 if (a == last) {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
142 break;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
143 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
144
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
145 a += PTE_SZ;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
146 pa += PTE_SZ;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
147 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
148
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
149 return 0;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
150 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
151
211
66db83ec1ec2 kpt_alloc_check_impl and freerange
tobaru
parents: 208
diff changeset
152 __code kpt_alloc_check_impl(struct vm_impl* vm_impl, __code next(...)) {
212
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
153 struct run* r;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
154 if ((r = kpt_mem.freelist) != NULL ) {
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
155 kpt_mem.freelist = r->next;
6e03cee9733e can use r
tobaru
parents: 211
diff changeset
156 }
213
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
157 release(&kpt_mem.lock);
211
66db83ec1ec2 kpt_alloc_check_impl and freerange
tobaru
parents: 208
diff changeset
158
213
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
159 if ((r == NULL) && ((r = kmalloc (PT_ORDER)) == NULL)) {
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
160 // panic("oom: kpt_alloc");
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
161 // goto panic
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
162 }
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
163
f4effd36aefc kpt_alloc
tobaru
parents: 212
diff changeset
164 memset(r, 0, PT_SZ);
211
66db83ec1ec2 kpt_alloc_check_impl and freerange
tobaru
parents: 208
diff changeset
165 goto next((char*)r);
66db83ec1ec2 kpt_alloc_check_impl and freerange
tobaru
parents: 208
diff changeset
166 }
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
167
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
168 __code allocuvm_check_newszvm_impl(struct vm_impl* vm_impl, pde_t* pgdir, uint oldsz, uint newsz, __code next(int ret, ...)){
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
169 if (newsz >= UADDR_SZ) {
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
170 goto next(0, ...);
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
171 }
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
172
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
173 if (newsz < oldsz) {
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
174 ret = newsz;
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
175 goto next(ret, ...);
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
176 }
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
177
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
178 char* mem;
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
179 uint a = align_up(oldsz, PTE_SZ);
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
180
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
181 goto allocuvm_loopvm_impl(vm_impl, pgdir, oldsz, newsz, mem, a, next(ret, ...));
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
182 }
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
183
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
184 __code allocuvm_loopvm_impl(struct vm_impl* vm_impl, pde_t* pgdir, uint oldsz, uint newsz, char* mem, uint a, __code next(int ret, ...)){
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
185
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
186 if (a < newsz) {
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
187 mem = alloc_page();
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
188
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
189 if (mem == 0) {
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
190 cprintf("allocuvm out of memory\n");
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
191 deallocuvm(pgdir, newsz, oldsz);
216
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
192 goto next(0, ...);
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
193 }
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
194
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
195 memset(mem, 0, PTE_SZ);
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
196 mappages(pgdir, (char*) a, PTE_SZ, v2p(mem), AP_KU);
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
197
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
198 goto allocuvm_loopvm_impl(vm_impl, pgdir, oldsz, newsz, a + PTE_SZ, next(ret, ...));
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
199 }
215
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
200 ret = newsz;
291d4e9304a1 allocuvm_loopvm_imp
tobaru
parents: 214
diff changeset
201 goto next(ret, ...);
214
2ecf1e09e981 allocuvm_loop and return
tobaru
parents: 213
diff changeset
202 }
216
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
203
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
204 __code clearpteu_check_ptevm_impl(struct vm_impl* vm_impl, pde_t* pgdir, char* uva, __code next(int ret, ...)) {
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
205 pte_t *pte;
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
206
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
207 pte = walkpgdir(pgdir, uva, 0);
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
208 if (pte == 0) {
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
209 // panic("clearpteu");
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
210 // goto panic;
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
211 }
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
212
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
213 // in ARM, we change the AP field (ap & 0x3) << 4)
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
214 *pte = (*pte & ~(0x03 << 4)) | AP_KO << 4;
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
215
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
216 goto next(ret, ...);
0f1700bd5cff cleapteu
tobaru
parents: 215
diff changeset
217 }
217
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
218
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
219 __code copyuvm_check_nullvm_impl(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, __code next(int ret, ...)) {
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
220 pde_t *d;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
221 pte_t *pte;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
222 uint pa, i, ap;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
223 char *mem;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
224
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
225 // allocate a new first level page directory
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
226 d = kpt_alloc();
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
227 if (d == NULL ) {
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
228 ret = NULL;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
229 goto next(ret, ...);
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
230 }
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
231 i = 0;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
232
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
233 goto copyuvm_loopvm_impl(vm_impl, pgdir, sz, *d, *pte, pa, i, ap, *mem, next(ret, ...));
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
234 }
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
235
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
236 __code copyuvm_loopvm_impl(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)) {
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
237
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
238 if (i < sz) {
218
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
239 goto copyuvm_loop_check_walkpgdir(vm_impl, pgdir, sz, d, pte, pa, i, ap, mem, __code next(int ret, ...));
217
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
240
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
241 }
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
242 ret = d;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
243 goto next(ret, ...);
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
244 }
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
245
218
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
246 __code copyuvm_loop_check_walkpgdir(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
247 if ((pte = walkpgdir(pgdir, (void *) i, 0)) == 0) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
248 // panic("copyuvm: pte should exist");
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
249 // goto panic();
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
250 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
251 goto copyuvm_loop_check_pte(vm_impl, pgdir, sz, d, pte, pa, i, ap, mem, __code next(int ret, ...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
252 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
253
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
254 __code copyuvm_loop_check_pte(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
255
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
256 if (!(*pte & PE_TYPES)) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
257 // panic("copyuvm: page not present");
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
258 // goto panic();
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
259 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
260
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
261 goto copyuvm_loop_check_mem(vm_impl, pgdir, sz, d, pte, pa, i, ap, mem, __code next(int ret, ...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
262 }
217
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
263
218
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
264 __code copyuvm_loop_check_mem(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
265 pa = PTE_ADDR (*pte);
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
266 ap = PTE_AP (*pte);
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
267
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
268 if ((mem = alloc_page()) == 0) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
269 goto copyuvm_loop_bad(vm_impl, d, next(...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
270 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
271 goto copyuvm_loop_check_mappages(vm_impl, pgdir, sz, d, pte, pa, i, ap, mem, __code next(int ret, ...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
272
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
273 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
274
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
275 __code copyuvm_loop_check_mappages(struct vm_impl* vm_impl, pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
276
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
277 memmove(mem, (char*) p2v(pa), PTE_SZ);
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
278
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
279 if (mappages(d, (void*) i, PTE_SZ, v2p(mem), ap) < 0) {
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
280 goto copyuvm_loop_bad(vm_impl, d, next(...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
281 }
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
282 goto copyuvm_loopvm_impl(vm_impl, pgdir, sz, d, pte, pa, i, ap, mem, __code next(int ret, ...));
1c923ae14607 copyuvm
tobaru
parents: 217
diff changeset
283
217
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
284 }
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
285
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
286 __code copyuvm_loop_bad(struct vm_impl* vm_impl, pde_t* d, __code next(int ret, ...)) {
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
287 freevm(d);
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
288 ret = 0;
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
289 goto next(ret, ...);
f940ff602312 copyuvm_loop
tobaru
parents: 216
diff changeset
290 }
220
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
291
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
292
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
293 __code uva2ka_check_pe_types(struct vm_impl* vm, pde_t* pgdir, char* uva, __code next(int ret, ...)) {
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
294 pte_t* pte;
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
295
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
296 pte = walkpgdir(pgdir, uva, 0);
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
297
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
298 // make sure it exists
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
299 if ((*pte & PE_TYPES) == 0) {
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
300 ret = 0;
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
301 goto next(ret, ...);
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
302 }
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
303 goto uva2ka_check_pte_ap(vm, pgdir, uva, pte, next(...));
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
304 }
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
305
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
306 __code uva2ka_check_pte_ap(struct vm_impl* vm, pde_t* pgdir, char* uva, pte_t* pte, __code next(int ret, ...)) {
221
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
307 // make sure it is a user page
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
308 if (PTE_AP(*pte) != AP_KU) {
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
309 ret = 0;
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
310 goto next(ret, ...);
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
311 }
098942ff5f44 uva2ka_check_pte_ap
tobaru
parents: 220
diff changeset
312 ret = (char*) p2v(PTE_ADDR(*pte));
220
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
313 goto next(ret, ...);
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
314 }
c1d1721fd907 uva2ka_check_pe_types
tobaru
parents: 219
diff changeset
315
222
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
316 // flush all TLB
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
317 static void flush_tlb (void)
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
318 {
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
319 uint val = 0;
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
320 asm("MCR p15, 0, %[r], c8, c7, 0" : :[r]"r" (val):);
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
321
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
322 // invalid entire data and instruction cache
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
323 asm ("MCR p15,0,%[r],c7,c10,0": :[r]"r" (val):);
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
324 asm ("MCR p15,0,%[r],c7,c11,0": :[r]"r" (val):);
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
325 }
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
326
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
327 __code paging_intvmvm_impl(struct vm_impl* vm_impl, uint phy_low, uint phy_hi, __code next(...)) {
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
328 mappages (P2V(&_kernel_pgtbl), P2V(phy_low), phy_hi - phy_low, phy_low, AP_KU);
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
329 flush_tlb ();
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
330
223
90b65036d9a2 paging_init
tobaru
parents: 222
diff changeset
331 goto next(...);
222
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
332 }
7a4d299a35be paging_init
tobaru
parents: 221
diff changeset
333
224
37900976db8e copyout
tobaru
parents: 223
diff changeset
334 __code copyout_loopvm_impl(struct vm_impl* vm_impl, pde_t* pgdir, uint va, void* pp, uint len, uint va0, char* pa0, __code next(int ret, ...)) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
335 if (len > 0) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
336 va0 = align_dn(va, PTE_SZ);
37900976db8e copyout
tobaru
parents: 223
diff changeset
337 pa0 = uva2ka(pgdir, (char*) va0);
37900976db8e copyout
tobaru
parents: 223
diff changeset
338 goto copyout_loop_check_pa0(vm_impl, pgdir, va, pp, len, va0, pa0, n, next(...));
37900976db8e copyout
tobaru
parents: 223
diff changeset
339 }
37900976db8e copyout
tobaru
parents: 223
diff changeset
340 ret = 0;
37900976db8e copyout
tobaru
parents: 223
diff changeset
341 goto next(ret, ...);
223
90b65036d9a2 paging_init
tobaru
parents: 222
diff changeset
342
90b65036d9a2 paging_init
tobaru
parents: 222
diff changeset
343 }
90b65036d9a2 paging_init
tobaru
parents: 222
diff changeset
344
224
37900976db8e copyout
tobaru
parents: 223
diff changeset
345 __code copyout_loop_check_pa0(struct vm_impl* vm_impl, pde_t* pgdir, uint va, void* pp, uint len, uint va0, char* pa0, uint n, __code next(int ret, ...)) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
346 if (pa0 == 0) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
347 ret = -1;
37900976db8e copyout
tobaru
parents: 223
diff changeset
348 goto next(ret, ...);
37900976db8e copyout
tobaru
parents: 223
diff changeset
349 }
37900976db8e copyout
tobaru
parents: 223
diff changeset
350 goto copyout_loop_check_n(vm_impl, pgdir, va, pp, len, va0, pa0, n, buf, next(...));
37900976db8e copyout
tobaru
parents: 223
diff changeset
351 }
37900976db8e copyout
tobaru
parents: 223
diff changeset
352 __code copyout_loop_check_n(struct vm_impl* vm_impl, pde_t* pgdir, uint va, void* pp, uint len, uint va0, char* pa0, uint n, char* buf, __code next(...)) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
353 n = PTE_SZ - (va - va0);
223
90b65036d9a2 paging_init
tobaru
parents: 222
diff changeset
354
224
37900976db8e copyout
tobaru
parents: 223
diff changeset
355 if (n > len) {
37900976db8e copyout
tobaru
parents: 223
diff changeset
356 n = len;
37900976db8e copyout
tobaru
parents: 223
diff changeset
357 }
37900976db8e copyout
tobaru
parents: 223
diff changeset
358
37900976db8e copyout
tobaru
parents: 223
diff changeset
359 len -= n;
37900976db8e copyout
tobaru
parents: 223
diff changeset
360 buf += n;
37900976db8e copyout
tobaru
parents: 223
diff changeset
361 va = va0 + PTE_SZ;
37900976db8e copyout
tobaru
parents: 223
diff changeset
362 goto copyout_loopvm_impl(vm_impl, pgdir, va, pp, len, va0, pa0, next(...));
37900976db8e copyout
tobaru
parents: 223
diff changeset
363 }
37900976db8e copyout
tobaru
parents: 223
diff changeset
364
226
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
365 typedef struct proc proc_struct;
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
366 __code switchuvm_check_pgdirvm_impl(struct vm_impl* vm_impl, proc_struct* p, __code next(...)) { //:skip
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
367 uint val;
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
368
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
369 pushcli();
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
370
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
371 if (p->pgdir == 0) {
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
372 panic("switchuvm: no pgdir");
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
373 }
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
374
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
375 val = (uint) V2P(p->pgdir) | 0x00;
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
376
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
377 asm("MCR p15, 0, %[v], c2, c0, 0": :[v]"r" (val):);
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
378 flush_tlb();
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
379
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
380 popcli();
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
381
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
382 goto next(...);
415081e357ec switchuvm_check_pgdirvm_impl
tobaru
parents: 224
diff changeset
383 }
227
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
384
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
385 __code init_inituvm_check_sz(struct vm_impl* vm_impl, pde_t* pgdir, char* init, uint sz, __code next(...)) {
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
386 char* mem;
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
387
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
388 if (sz >= PTE_SZ) {
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
389 // goto panic;
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
390 // panic("inituvm: more than a page");
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
391 }
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
392
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
393 mem = alloc_page();
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
394 memset(mem, 0, PTE_SZ);
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
395 mappages(pgdir, 0, PTE_SZ, v2p(mem), AP_KU);
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
396 memmove(mem, init, sz);
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
397
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
398 goto next(...);
80398e02ae72 init_inituvm
tobaru
parents: 226
diff changeset
399 }
269
bd948528b2d6 impl_vm_void_ret
anatofuz
parents: 227
diff changeset
400