|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "io.h"
7:
8: /*
9: * segment descriptor initializers
10: */
11: #define DATASEGM(p) (Segdesc){ 0xFFFF,\
12: SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
13: #define EXECSEGM(p) (Segdesc){ 0xFFFF,\
14: SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
15: #define CALLGATE(s,o,p) (Segdesc){ ((o)&0xFFFF)|((s)<<16),\
16: (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG }
17: #define D16SEGM(p) (Segdesc){ 0xFFFF,\
18: (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
19: #define E16SEGM(p) (Segdesc){ 0xFFFF,\
20: (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
21: #define TSSSEGM(b,p) (Segdesc){ ((b)<<16)|sizeof(Tss),\
22: ((b)&0xFF000000)|(((b)>>16)&0xFF)|SEGTSS|SEGPL(p)|SEGP }
23:
24: static Page ktoppg; /* prototype top level page table
25: * containing kernel mappings */
26: static ulong *kpt; /* 2nd level page tables for kernel mem */
27: static ulong *upt; /* 2nd level page table for struct User */
28:
29: #define ROUNDUP(s,v) (((s)+(v-1))&~(v-1))
30: /*
31: * offset of virtual address into
32: * top level page table
33: */
34: #define TOPOFF(v) (((ulong)(v))>>(2*PGSHIFT-2))
35:
36: /*
37: * offset of virtual address into
38: * bottom level page table
39: */
40: #define BTMOFF(v) ((((ulong)(v))>>(PGSHIFT))&(WD2PG-1))
41:
42: #define MAXUMEG 64 /* maximum memory per user process in megabytes */
43: #define ONEMEG (1024*1024)
44:
45: enum {
46: Nisa= 256,
47: };
48: struct
49: {
50: Lock;
51: ulong s[Nisa];
52: ulong e[Nisa];
53: } isaalloc;
54:
55: /*
56: * setup mmu for a cpu assuming we've already created the kernel
57: * page tables.
58: */
59: void
60: setupmmu(void)
61: {
62: ulong x;
63:
64: /*
65: * set up the global descriptor table. we make the tss entry here
66: * since it requires arithmetic on an address and hence cannot
67: * be a compile or link time constant.
68: */
69: x = (ulong)&m->tss;
70: m->gdt[NULLSEG] = (Segdesc){0, 0};
71: m->gdt[TSSSEG] = TSSSEGM(x, 0);
72: m->gdt[KDSEG] = DATASEGM(0); /* kernel data/stack */
73: m->gdt[KESEG] = EXECSEGM(0); /* kernel code */
74: m->gdt[UDSEG] = DATASEGM(3); /* user data/stack */
75: m->gdt[UESEG] = EXECSEGM(3); /* user code */
76: putgdt(m->gdt, sizeof(m->gdt));
77:
78: /*
79: * point to kernel page table
80: */
81: putcr3(ktoppg.pa);
82:
83: /*
84: * set up the task segment
85: */
86: memset(&m->tss, 0, sizeof(m->tss));
87: m->tss.sp0 = USERADDR+BY2PG;
88: m->tss.ss0 = KDSEL;
89: m->tss.cr3 = ktoppg.pa;
90: puttr(TSSSEL);
91: }
92:
93: /*
94: * Create a prototype page map that maps all of memory into
95: * kernel (KZERO) space. This is the default map. It is used
96: * whenever the processor not running a process or whenever running
97: * a process which does not yet have its own map.
98: */
99: void
100: mmuinit(void)
101: {
102: int i, nkpt, npage, nbytes;
103: ulong x;
104: ulong y;
105: ulong *top;
106:
107: /*
108: * set up system page tables.
109: * map all of physical memory to start at KZERO.
110: * leave a map entry for a user area.
111: */
112:
113: /* allocate top level table */
114: top = xspanalloc(BY2PG, BY2PG, 0);
115: ktoppg.va = (ulong)top;
116: ktoppg.pa = ktoppg.va & ~KZERO;
117:
118: /* map all memory to KZERO */
119: npage = 128*MB/BY2PG;
120: nbytes = PGROUND(npage*BY2WD); /* words of page map */
121: nkpt = nbytes/BY2PG; /* pages of page map */
122: kpt = xspanalloc(nbytes, BY2PG, 0);
123: for(i = 0; i < npage; i++)
124: kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;
125: x = TOPOFF(KZERO);
126: y = ((ulong)kpt)&~KZERO;
127: for(i = 0; i < nkpt; i++)
128: top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;
129:
130: /* page table for u-> */
131: upt = xspanalloc(BY2PG, BY2PG, 0);
132: x = TOPOFF(USERADDR);
133: y = ((ulong)upt)&~KZERO;
134: top[x] = y | PTEVALID | PTEKERNEL | PTEWRITE;
135:
136: setupmmu();
137: }
138:
139: /*
140: * Mark the mmu and tlb as inconsistent and call mapstack to fix it up.
141: */
142: void
143: flushmmu(void)
144: {
145: int s;
146:
147: s = splhi();
148: if(u){
149: u->p->newtlb = 1;
150: mapstack(u->p);
151: } else
152: putcr3(ktoppg.pa);
153: splx(s);
154: }
155:
156: /*
157: * Switch to a process's memory map. If the process doesn't
158: * have a map yet, just use the prototype one that contains
159: * mappings for only the kernel and the User struct.
160: */
161: void
162: mapstack(Proc *p)
163: {
164: Page *pg;
165: ulong *top;
166:
167: if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0)
168: panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
169:
170: if(p->newtlb){
171: /*
172: * newtlb set means that they are inconsistent
173: * with the segment.c data structures.
174: *
175: * bin the current second level page tables and
176: * the pointers to them in the top level page.
177: * pg->daddr is used by putmmu to save the offset into
178: * the top level page.
179: */
180: if(p->mmutop && p->mmuused){
181: top = (ulong*)p->mmutop->va;
182: for(pg = p->mmuused; pg->next; pg = pg->next)
183: ilputl(&top[pg->daddr], 0);
184: ilputl(&top[pg->daddr], 0);
185: pg->next = p->mmufree;
186: p->mmufree = p->mmuused;
187: p->mmuused = 0;
188: }
189: p->newtlb = 0;
190: }
191:
192: /* map in u area */
193: upt[0] = PPN(p->upage->pa) | PTEVALID | PTEKERNEL | PTEWRITE;
194:
195: /* tell processor about new page table (flushes cached entries) */
196: if(p->mmutop)
197: pg = p->mmutop;
198: else
199: pg = &ktoppg;
200: putcr3(pg->pa);
201:
202: u = (User*)USERADDR;
203: }
204:
205: /*
206: * give all page table pages back to the free pool. This is called in sched()
207: * with palloc locked.
208: */
209: void
210: mmurelease(Proc *p)
211: {
212: Page *pg;
213: Page *next;
214:
215: /* point 386 to protoype page map */
216: putcr3(ktoppg.pa);
217:
218: /* give away page table pages */
219: for(pg = p->mmufree; pg; pg = next){
220: next = pg->next;
221: simpleputpage(pg);
222: }
223: p->mmufree = 0;
224: for(pg = p->mmuused; pg; pg = next){
225: next = pg->next;
226: simpleputpage(pg);
227: }
228: p->mmuused = 0;
229: if(p->mmutop)
230: simpleputpage(p->mmutop);
231: p->mmutop = 0;
232: }
233:
234: /*
235: * Add an entry into the mmu.
236: */
237: void
238: putmmu(ulong va, ulong pa, Page *pg)
239: {
240: int topoff;
241: ulong *top;
242: ulong *pt;
243: Proc *p;
244: int s;
245:
246: if(u==0)
247: panic("putmmu");
248: p = u->p;
249:
250: /*
251: * create a top level page if we don't already have one.
252: * copy the kernel top level page into it for kernel mappings.
253: */
254: if(p->mmutop == 0){
255: pg = newpage(0, 0, 0);
256: pg->va = VA(kmap(pg));
257: memmove((void*)pg->va, (void*)ktoppg.va, BY2PG);
258: p->mmutop = pg;
259: }
260: top = (ulong*)p->mmutop->va;
261: topoff = TOPOFF(va);
262:
263: /*
264: * if bottom level page table missing, allocate one
265: * and point the top level page at it.
266: */
267: s = splhi();
268: if(PPN(top[topoff]) == 0){
269: if(p->mmufree == 0){
270: spllo();
271: pg = newpage(1, 0, 0);
272: pg->va = VA(kmap(pg));
273: splhi();
274: } else {
275: pg = p->mmufree;
276: p->mmufree = pg->next;
277: memset((void*)pg->va, 0, BY2PG);
278: }
279: ilputl(&top[topoff], PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE);
280: pg->daddr = topoff;
281: pg->next = p->mmuused;
282: p->mmuused = pg;
283: }
284:
285: /*
286: * put in new mmu entry
287: */
288: pt = (ulong*)(PPN(top[topoff])|KZERO);
289: ilputl(&pt[BTMOFF(va)], pa | PTEUSER);
290:
291: /* flush cached mmu entries */
292: putcr3(p->mmutop->pa);
293: splx(s);
294: }
295:
296: void
297: invalidateu(void)
298: {
299: /* unmap u area */
300: upt[0] = 0;
301:
302: /* flush cached mmu entries */
303: putcr3(ktoppg.pa);
304: }
305:
306: /*
307: * used to map a page into 16 meg - BY2PG for confinit(). tpt is the temporary
308: * page table set up by l.s.
309: */
310: long*
311: mapaddr(ulong addr)
312: {
313: ulong base;
314: ulong off;
315: static ulong *pte, top;
316: extern ulong tpt[];
317:
318: if(pte == 0){
319: top = (((ulong)tpt)+(BY2PG-1))&~(BY2PG-1);
320: pte = (ulong*)top;
321: top &= ~KZERO;
322: top += BY2PG;
323: pte += (4*1024*1024-BY2PG)>>PGSHIFT;
324: }
325:
326: base = off = addr;
327: base &= ~(KZERO|(BY2PG-1));
328: off &= BY2PG-1;
329:
330: *pte = base|PTEVALID|PTEKERNEL|PTEWRITE; /**/
331: putcr3((ulong)top);
332:
333: return (long*)(KZERO | 4*1024*1024-BY2PG | off);
334: }
335:
336: /*
337: * make isa address space available
338: */
339: void
340: putisa(ulong addr, int len)
341: {
342: ulong e;
343: int i, hole;
344:
345: addr &= ~KZERO;
346:
347: e = addr + len;
348: lock(&isaalloc);
349: hole = -1;
350: for(i = 0; i < Nisa; i++){
351: if(isaalloc.s[i] == e){
352: isaalloc.s[i] = addr;
353: break;
354: }
355: if(isaalloc.e[i] == addr){
356: isaalloc.e[i] = e;
357: break;
358: }
359: if(isaalloc.s[i] == 0)
360: hole = i;
361: }
362: if(i >= Nisa && hole >= 0){
363: isaalloc.s[hole] = addr;
364: isaalloc.e[hole] = e;
365: }
366: unlock(&isaalloc);
367: }
368:
369: /*
370: * allocate some address space (already mapped into the kernel)
371: * for ISA bus memory.
372: */
373: ulong
374: getisa(ulong addr, int len, int align)
375: {
376: int i;
377: long os, s, e;
378:
379: lock(&isaalloc);
380: os = s = e = 0;
381: for(i = 0; i < Nisa; i++){
382: s = os = isaalloc.s[i];
383: if(s == 0)
384: continue;
385: e = isaalloc.e[i];
386: if(addr && addr >= s && addr < e)
387: break;
388: if(align > 0)
389: s = ((s + align - 1)/align)*align;
390: if(e - s >= len)
391: break;
392: }
393: if(i >= Nisa){
394: unlock(&isaalloc);
395: return 0;
396: }
397:
398: /* remove */
399: isaalloc.s[i] = 0;
400: unlock(&isaalloc);
401:
402: /* give back edges */
403: if(s != os)
404: putisa(os, s - os);
405: os = s + len;
406: if(os != e)
407: putisa(os, e - os);
408:
409: return KZERO|s;
410: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.