|
|
1.1 root 1: /*
2: * Copyright (c) 1988 University of Utah.
3: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4: * All rights reserved.
5: *
6: * This code is derived from software contributed to Berkeley by
7: * the Systems Programming Group of the University of Utah Computer
8: * Science Department.
9: *
10: * Redistribution is only permitted until one year after the first shipment
11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
12: * binary forms are permitted provided that: (1) source distributions retain
13: * this entire copyright notice and comment, and (2) distributions including
14: * binaries display the following acknowledgement: This product includes
15: * software developed by the University of California, Berkeley and its
16: * contributors'' in the documentation or other materials provided with the
17: * distribution and in all advertising materials mentioning features or use
18: * of this software. Neither the name of the University nor the names of
19: * its contributors may be used to endorse or promote products derived from
20: * this software without specific prior written permission.
21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24: *
25: * from: Utah $Hdr: vm_machdep.c 1.18 89/08/23$
26: *
27: * @(#)vm_machdep.c 7.5 (Berkeley) 6/21/90
28: */
29:
30: #include "param.h"
31: #include "systm.h"
32: #include "user.h"
33: #include "proc.h"
34: #include "cmap.h"
35: #include "vm.h"
36: #include "text.h"
37: #include "malloc.h"
38: #include "buf.h"
39:
40: #include "cpu.h"
41: #include "pte.h"
42:
43: /*
44: * Set a red zone in the kernel stack after the u. area.
45: * We don't support a redzone right now. It really isn't clear
46: * that it is a good idea since, if the kernel stack were to roll
47: * into a write protected page, the processor would lock up (since
48: * it cannot create an exception frame) and we would get no useful
49: * post-mortem info. Currently, under the DEBUG option, we just
50: * check at every clock interrupt to see if the current k-stack has
51: * gone too far (i.e. into the "redzone" page) and if so, panic.
52: * Look at _lev6intr in locore.s for more details.
53: */
54: /*ARGSUSED*/
55: setredzone(pte, vaddr)
56: struct pte *pte;
57: caddr_t vaddr;
58: {
59: }
60:
61: /*
62: * Check for valid program size
63: * NB - Check data and data growth separately as they may overflow
64: * when summed together.
65: */
66: chksize(ts, ids, uds, ss)
67: unsigned ts, ids, uds, ss;
68: {
69: extern unsigned maxtsize;
70:
71: if (ctob(ts) > maxtsize ||
72: ctob(ids) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
73: ctob(uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
74: ctob(ids + uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
75: ctob(ss) > u.u_rlimit[RLIMIT_STACK].rlim_cur) {
76: return (ENOMEM);
77: }
78: return (0);
79: }
80:
81: /*ARGSUSED*/
82: newptes(pte, v, size)
83: struct pte *pte;
84: u_int v;
85: register int size;
86: {
87: register caddr_t a;
88:
89: #ifdef lint
90: pte = pte;
91: #endif
92: if (size >= 8)
93: TBIAU();
94: else {
95: a = ptob(v);
96: while (size > 0) {
97: TBIS(a);
98: a += NBPG;
99: size--;
100: }
101: }
102: DCIU();
103: }
104:
105: /*
106: * Change protection codes of text segment.
107: * Have to flush translation buffer since this
108: * affect virtual memory mapping of current process.
109: */
110: chgprot(addr, tprot)
111: caddr_t addr;
112: long tprot;
113: {
114: unsigned v;
115: int tp;
116: register struct pte *pte;
117: register struct cmap *c;
118:
119: v = clbase(btop(addr));
120: if (!isatsv(u.u_procp, v))
121: return (EFAULT);
122: tp = vtotp(u.u_procp, v);
123: pte = tptopte(u.u_procp, tp);
124: if (pte->pg_fod == 0 && pte->pg_pfnum) {
125: c = &cmap[pgtocm(pte->pg_pfnum)];
126: if (c->c_blkno)
127: munhash(c->c_vp, (daddr_t)(u_long)c->c_blkno);
128: }
129: *(u_int *)pte &= ~PG_PROT;
130: *(u_int *)pte |= tprot;
131: TBIS(addr);
132: return (0);
133: }
134:
135: settprot(tprot)
136: long tprot;
137: {
138: register u_int *pte, i;
139:
140: pte = (u_int *)u.u_procp->p_p0br;
141: for (i = 0; i < u.u_tsize; i++, pte++) {
142: *pte &= ~PG_PROT;
143: *pte |= tprot;
144: }
145: TBIAU();
146: }
147:
148: /*
149: * Simulate effect of VAX region length registers.
150: * The one case where we must do anything is if a region has shrunk.
151: * In that case we must invalidate all the PTEs for the no longer valid VAs.
152: */
153: setptlr(region, nlen)
154: int nlen;
155: {
156: register struct pte *pte;
157: register int change;
158: int olen;
159:
160: if (region == 0) {
161: olen = u.u_pcb.pcb_p0lr;
162: u.u_pcb.pcb_p0lr = nlen;
163: } else {
164: olen = P1PAGES - u.u_pcb.pcb_p1lr;
165: u.u_pcb.pcb_p1lr = nlen;
166: nlen = P1PAGES - nlen;
167: }
168: if ((change = olen - nlen) <= 0)
169: return;
170: if (region == 0)
171: pte = u.u_pcb.pcb_p0br + u.u_pcb.pcb_p0lr;
172: else
173: pte = u.u_pcb.pcb_p1br + u.u_pcb.pcb_p1lr - change;
174: do {
175: *(u_int *)pte++ = PG_NV;
176: } while (--change);
177: /* short cut newptes */
178: TBIAU();
179: DCIU();
180: }
181:
182: /*
183: * Map `size' bytes of physical memory starting at `paddr' into
184: * kernel VA space using PTEs starting at `pte'. Read/write and
185: * cache-inhibit status are specified by `prot'.
186: */
187: physaccess(pte, paddr, size, prot)
188: register struct pte *pte;
189: caddr_t paddr;
190: register int size;
191: {
192: register u_int page;
193:
194: page = (u_int)paddr & PG_FRAME;
195: for (size = btoc(size); size; size--) {
196: *(int *)pte = PG_V | prot | page;
197: page += NBPG;
198: pte++;
199: }
200: TBIAS();
201: }
202:
203: /*
204: * Move pages from one kernel virtual address to another.
205: * Both addresses are assumed to reside in the Sysmap,
206: * and size must be a multiple of CLSIZE.
207: */
208: pagemove(from, to, size)
209: register caddr_t from, to;
210: int size;
211: {
212: register struct pte *fpte, *tpte;
213:
214: if (size % CLBYTES)
215: panic("pagemove");
216: fpte = kvtopte(from);
217: tpte = kvtopte(to);
218: while (size > 0) {
219: *tpte++ = *fpte;
220: *(int *)fpte++ = PG_NV;
221: TBIS(from);
222: TBIS(to);
223: from += NBPG;
224: to += NBPG;
225: size -= NBPG;
226: }
227: }
228:
229: #ifdef KGDB
230: /*
231: * Change protections on kernel pages from addr to addr+size
232: * (presumably so debugger can plant a breakpoint).
233: * All addresses are assumed to reside in the Sysmap,
234: */
235: chgkprot(addr, size, rw)
236: register caddr_t addr;
237: int size, rw;
238: {
239: register struct pte *pte;
240:
241: pte = &Sysmap[btop(addr)];
242: while (size > 0) {
243: pte->pg_prot = rw == B_WRITE? 0 : 1;
244: TBIS(addr);
245: addr += NBPG;
246: size -= NBPG;
247: pte++;
248: }
249: }
250: #endif
251:
252: /*
253: * The probe[rw] routines should probably be redone in assembler
254: * for efficiency.
255: */
256: prober(addr)
257: register u_int addr;
258: {
259: register int page;
260: register struct proc *p;
261:
262: if (addr >= USRSTACK)
263: return(0);
264: #ifdef HPUXCOMPAT
265: if (ISHPMMADDR(addr))
266: addr = HPMMBASEADDR(addr);
267: #endif
268: page = btop(addr);
269: p = u.u_procp;
270: if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
271: return(1);
272: #ifdef MAPMEM
273: if (page < dptov(p, p->p_dsize+p->p_mmsize) &&
274: (*(int *)vtopte(p, page) & (PG_FOD|PG_V)) == (PG_FOD|PG_V))
275: return(1);
276: #endif
277: return(0);
278: }
279:
280: probew(addr)
281: register u_int addr;
282: {
283: register int page;
284: register struct proc *p;
285:
286: if (addr >= USRSTACK)
287: return(0);
288: #ifdef HPUXCOMPAT
289: if (ISHPMMADDR(addr))
290: addr = HPMMBASEADDR(addr);
291: #endif
292: page = btop(addr);
293: p = u.u_procp;
294: if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
295: return((*(int *)vtopte(p, page) & PG_PROT) == PG_RW);
296: #ifdef MAPMEM
297: if (page < dptov(p, p->p_dsize+p->p_mmsize))
298: return((*(int *)vtopte(p, page) & (PG_FOD|PG_V|PG_PROT))
299: == (PG_FOD|PG_V|PG_RW));
300: #endif
301: return(0);
302: }
303:
304: /*
305: * NB: assumes a physically contiguous kernel page table
306: * (makes life a LOT simpler).
307: */
308: kernacc(addr, count, rw)
309: register caddr_t addr;
310: int count, rw;
311: {
312: register struct ste *ste;
313: register struct pte *pte;
314: register u_int ix, cnt;
315: extern long Syssize;
316:
317: if (count <= 0)
318: return(0);
319: ix = ((int)addr & SG_IMASK) >> SG_ISHIFT;
320: cnt = (((int)addr + count + (1<<SG_ISHIFT)-1) & SG_IMASK) >> SG_ISHIFT;
321: cnt -= ix;
322: for (ste = &Sysseg[ix]; cnt; cnt--, ste++)
323: /* should check SG_PROT, but we have no RO segments now */
324: if (ste->sg_v == 0)
325: return(0);
326: ix = btop(addr);
327: cnt = btop(addr+count+NBPG-1);
328: if (cnt > (u_int)&Syssize)
329: return(0);
330: cnt -= ix;
331: for (pte = &Sysmap[ix]; cnt; cnt--, pte++)
332: if (pte->pg_v == 0 || (rw == B_WRITE && pte->pg_prot == 1))
333: return(0);
334: return(1);
335: }
336:
337: useracc(addr, count, rw)
338: register caddr_t addr;
339: unsigned count;
340: {
341: register int (*func)();
342: register u_int addr2;
343: extern int prober(), probew();
344:
345: if (count <= 0)
346: return(0);
347: addr2 = (u_int) addr;
348: addr += count;
349: func = (rw == B_READ) ? prober : probew;
350: do {
351: if ((*func)(addr2) == 0)
352: return(0);
353: addr2 = (addr2 + NBPG) & ~PGOFSET;
354: } while (addr2 < (u_int)addr);
355: return(1);
356: }
357:
358: /*
359: * Convert kernel VA to physical address
360: */
361: kvtop(addr)
362: register caddr_t addr;
363: {
364: register int pf;
365:
366: pf = Sysmap[btop(addr)].pg_pfnum;
367: if (pf == 0)
368: panic("kvtop: zero page frame");
369: return((u_int)ptob(pf) + ((int)addr & PGOFSET));
370: }
371:
372: struct ste *
373: vtoste(p, va)
374: register struct proc *p;
375: register u_int va;
376: {
377: register struct ste *ste;
378:
379: ste = (struct ste *)((u_int)p->p_p0br + p->p_szpt * NBPG);
380: return(ste + ((va & SG_IMASK) >> SG_ISHIFT));
381: }
382:
383: initustp(p)
384: register struct proc *p;
385: {
386: return((int)Usrptmap[btokmx(p->p_p0br) + p->p_szpt].pg_pfnum);
387: }
388:
389: /*
390: * Initialize segment table to reflect PTEs in Usrptmap.
391: * Segment table address is given by Usrptmap index of p_szpt.
392: */
393: initsegt(p)
394: register struct proc *p;
395: {
396: register int i, k, sz;
397: register struct ste *ste;
398: extern struct ste *vtoste();
399:
400: k = btokmx(p->p_p0br);
401: ste = vtoste(p, 0);
402: /* text and data */
403: sz = ctopt(p->p_tsize + p->p_dsize + p->p_mmsize);
404: for (i = 0; i < sz; i++, ste++) {
405: *(int *)ste = SG_RW | SG_V;
406: ste->sg_pfnum = Usrptmap[k++].pg_pfnum;
407: }
408: /*
409: * Bogus! The kernelmap may map unused PT pages
410: * (since we don't shrink PTs) so we need to skip over
411: * those STEs. We should really free the unused PT
412: * pages in expand().
413: */
414: sz += ctopt(p->p_ssize + HIGHPAGES);
415: if (sz < p->p_szpt)
416: k += p->p_szpt - sz;
417: /* hole */
418: sz = NPTEPG - ctopt(p->p_ssize + HIGHPAGES);
419: for ( ; i < sz; i++, ste++)
420: *(int *)ste = SG_NV;
421: /* stack and u-area */
422: sz = NPTEPG;
423: for ( ; i < sz; i++, ste++) {
424: *(int *)ste = SG_RW | SG_V;
425: ste->sg_pfnum = Usrptmap[k++].pg_pfnum;
426: }
427: }
428:
429: /*
430: * Allocate/free cache-inhibited physical memory.
431: * Assumes that malloc returns page aligned memory for requests which are
432: * a multiple of the page size. Hence, size must be such a multiple.
433: */
434: caddr_t
435: cialloc(sz)
436: int sz;
437: {
438: caddr_t kva;
439: register int npg, *pte;
440:
441: if (sz & CLOFSET)
442: return(NULL);
443: kva = (caddr_t)malloc(sz, M_DEVBUF, M_NOWAIT);
444: if (kva) {
445: if (!claligned(kva))
446: panic("cialloc");
447: pte = (int *)kvtopte(kva);
448: npg = btoc(sz);
449: while (--npg >= 0)
450: *pte++ |= PG_CI;
451: TBIAS();
452: }
453: return(kva);
454: }
455:
456: cifree(kva, sz)
457: caddr_t kva;
458: int sz;
459: {
460: register int npg, *pte;
461:
462: if (sz & CLOFSET)
463: panic("cifree");
464: pte = (int *)kvtopte(kva);
465: npg = btoc(sz);
466: while (--npg >= 0)
467: *pte++ &= ~PG_CI;
468: TBIAS();
469: free(kva, M_DEVBUF);
470: }
471:
472: extern char usrio[];
473: extern struct pte Usriomap[];
474: struct map *useriomap;
475: int usriowanted;
476:
477: /*
478: * Map an IO request into kernel virtual address space. Requests fall into
479: * one of five catagories:
480: *
481: * B_PHYS|B_UAREA: User u-area swap.
482: * Address is relative to start of u-area (p_addr).
483: * B_PHYS|B_PAGET: User page table swap.
484: * Address is a kernel VA in usrpt (Usrptmap).
485: * B_PHYS|B_DIRTY: Dirty page push.
486: * Address is a VA in proc2's address space.
487: * B_PHYS|B_PGIN: Kernel pagein of user pages.
488: * Address is VA in user's address space.
489: * B_PHYS: User "raw" IO request.
490: * Address is VA in user's address space.
491: *
492: * All requests are (re)mapped into kernel VA space via the useriomap
493: * (a name with only slightly more meaning than "kernelmap")
494: */
495: vmapbuf(bp)
496: register struct buf *bp;
497: {
498: register int npf, a;
499: register caddr_t addr;
500: register struct pte *pte, *iopte;
501: register long flags = bp->b_flags;
502: struct proc *p;
503: int off, s;
504:
505: if ((flags & B_PHYS) == 0)
506: panic("vmapbuf");
507: /*
508: * Find PTEs for the area to be mapped
509: */
510: p = flags&B_DIRTY ? &proc[2] : bp->b_proc;
511: addr = bp->b_un.b_addr;
512: if (flags & B_UAREA)
513: pte = &p->p_addr[btop(addr)];
514: else if (flags & B_PAGET)
515: pte = &Usrptmap[btokmx((struct pte *)addr)];
516: else
517: pte = vtopte(p, btop(addr));
518: /*
519: * Allocate some kernel PTEs and load them
520: */
521: off = (int)addr & PGOFSET;
522: npf = btoc(bp->b_bcount + off);
523: s = splbio();
524: while ((a = rmalloc(useriomap, npf)) == 0) {
525: usriowanted = 1;
526: sleep((caddr_t)useriomap, PSWP);
527: }
528: splx(s);
529: iopte = &Usriomap[a];
530: bp->b_saveaddr = bp->b_un.b_addr;
531: addr = bp->b_un.b_addr = (caddr_t)(usrio + (a << PGSHIFT)) + off;
532: while (npf--) {
533: mapin(iopte, (u_int)addr, pte->pg_pfnum, PG_CI|PG_RW|PG_V);
534: iopte++, pte++;
535: addr += NBPG;
536: }
537: }
538:
539: /*
540: * Free the io map PTEs associated with this IO operation.
541: * We also invalidate the TLB entries and restore the original b_addr.
542: */
543: vunmapbuf(bp)
544: register struct buf *bp;
545: {
546: register int a, npf;
547: register caddr_t addr = bp->b_un.b_addr;
548: register struct pte *pte;
549: int s;
550:
551: if ((bp->b_flags & B_PHYS) == 0)
552: panic("vunmapbuf");
553: a = (int)(addr - usrio) >> PGSHIFT;
554: npf = btoc(bp->b_bcount + ((int)addr & PGOFSET));
555: s = splbio();
556: rmfree(useriomap, npf, a);
557: if (usriowanted) {
558: usriowanted = 0;
559: wakeup((caddr_t)useriomap);
560: }
561: splx(s);
562: pte = &Usriomap[a];
563: while (npf--) {
564: *(int *)pte = PG_NV;
565: TBIS((caddr_t)addr);
566: addr += NBPG;
567: pte++;
568: }
569: bp->b_un.b_addr = bp->b_saveaddr;
570: bp->b_saveaddr = NULL;
571: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.