|
|
1.1 root 1: /*
2:
3: * Copyright 1991,1992,1993 Atari Corporation.
4:
5: * All rights reserved.
6:
7: */
8:
9:
10:
11: /*
12:
13: * page-table data structures
14:
15: *
16:
17: *
18:
19: * The root pointer points to a list of pointers to top-level pointer tables.
20:
21: *
22:
23: * Each entry in a pointer table points to another pointer table or to
24:
25: * a page table, or is a page descriptor.
26:
27: *
28:
29: * Since, initially, the logical address space is the physical address space,
30:
31: * we only need to worry about 26MB plus 32K for I/O space.
32:
33: *
34:
35: * Since we want some pages to be supervisor-accessible, but we don't want
36:
37: * a whole separate table for that, we use long-format descriptors.
38:
39: *
40:
41: * Initial memory map:
42:
43: *
44:
45: * 0 - membot: S (supervisor only)
46:
47: * membot - memtop: P (protected TPA)
48:
49: * memtop - phystop: G (screen)
50:
51: * phystop - $00E00000: bus error
52:
53: * $00E00000- $00E3FFFF: G (ROM)
54:
55: * $00E40000- $00FF7FFF: bus error
56:
57: * $00FF8000- $00FFFFFF: G (mostly S: I/O space, but that's done in hardware)
58:
59: * $01000000- ramtop: P
60:
61: * ramtop - $7FFFFFFF: G (A32/D32 VME, cacheable)
62:
63: * $80000000- $FEFFFFFF: G (A32/D32 VME, non cacheable)
64:
65: * $FFxxxxxx just like $00xxxxxx.
66:
67: *
68:
69: * Here's a final choice of layouts: IS=0, PS=13 (8K), TIA=4, TIB=4, TIC=4,
70:
71: * TID=7. This lets us map out entire unused megabytes at level C, and gives
72:
73: * us an 8K page size, which is the largest the '040 can deal with.
74:
75: *
76:
77: * This code implements 4+4+4+7, as follows:
78:
79: *
80:
81: * tbl_a
82:
83: * 0 -> tbl_b0
84:
85: * 1-7 -> Cacheable direct (VME) page descriptors
86:
87: * 8-E -> Non-cacheable direct (VME) page descriptors
88:
89: * F -> tbl_bf
90:
91: *
92:
93: * tbl_b0 table: 16 entries (assumes only 16MB of TT RAM)
94:
95: * 0 -> tbl_c00 (16MB of ST RAM address space)
96:
97: * 1 -> tbl_c01 (16MB of TT RAM address space)
98:
99: * 2-F -> cacheable direct (VME) page descriptors
100:
101: *
102:
103: * tbl_bF table: 16 entries (deals with $FF mapping to $00)
104:
105: * 0-E -> Non-cacheable direct (VME) page descriptors
106:
107: * F -> tbl_c00 (16MB of ST RAM address space, repeated here as $FF)
108:
109: *
110:
111: * tbl_c00 table: ST RAM address space (example assuming 4MB ST RAM)
112:
113: * 0-3 -> RAM page tables
114:
115: * 4-D -> invalid
116:
117: * E -> direct map, cache enable (ROM)
118:
119: * F -> direct map, cache inhibit (I/O)
120:
121: *
122:
123: * For each 16MB containing any TT RAM, there's a tbl_c. Within those,
124:
125: * for each MB that actually has TT RAM, there's another table, containing
126:
127: * 128 RAM page tables. Where there isn't RAM, there are "global"
128:
129: * pages, to let the hardware bus error or not as it sees fit.
130:
131: *
132:
133: * One RAM page table is allocated per megabyte of real RAM; each table has
134:
135: * 128 entries, which is 8K per page. For a TT with 4MB ST RAM and 4MB TT RAM
136:
137: * that's 8K in page tables. You can cut this down by not allocating page
138:
139: * tables for which the entire megabyte is not accessible (i.e. it's all
140:
141: * private memory and it's not YOUR private memory).
142:
143: *
144:
145: * You have one of these per process. When somebody loads into G or S memory
146:
147: * or leaves it, you have to go through the page tables of every process
148:
149: * updating S bits (for S) and DT (for G) bits.
150:
151: *
152:
153: * The top levels are small & easy so replicating them once per process
154:
155: * doesn't really hurt us.
156:
157: *
158:
159: */
160:
161:
162:
163: #include "mint.h"
164:
165:
166:
167: #if 0
168:
169: #define MP_DEBUG(x) DEBUG(x)
170:
171: #else
172:
173: #define MP_DEBUG(x)
174:
175: #endif
176:
177:
178:
179: void *memset P_((void *s, int ucharfill, unsigned long size));
180:
181: static void _dump_tree P_((long_desc tbl, int level));
182:
183:
184:
185: extern int debug_level; /* see debug.c */
186:
1.1.1.2 root 187: extern long mcpu; /* in main.c */
188:
1.1 root 189:
190:
191: /*
192:
193: * You can turn this whole module off, and the stuff in context.s,
194:
195: * by setting no_mem_prot to 1.
196:
197: */
198:
199:
200:
201: int no_mem_prot;
202:
203: long page_table_size;
204:
205:
206:
207: /*
208:
209: * PMMU stuff
210:
211: */
212:
213:
214:
215: /*
216:
217: * This is one global TC register that is copied into every process'
218:
219: * context, even though it never changes. It's also used by the
220:
221: * functions that dump page tables.
222:
223: */
224:
225:
226:
227: tc_reg tc;
228:
229:
230:
231: /* mint_top_* get used in mem.c also */
232:
233: ulong mint_top_tt;
234:
235: ulong mint_top_st;
236:
237:
238:
239: int tt_mbytes; /* number of megabytds of TT RAM */
240:
241:
242:
243: /*
244:
245: * global_mode_table: one byte per page in the system. Initially all pages
246:
247: * are set to "global" but then the TPA pages are set to "invalid" in
248:
249: * init_mem. This has to be allocated and initialized in init_tables,
250:
251: * when you know how much memory there is. You need a byte per page,
252:
253: * from zero to the end of TT RAM, including the space between STRAM
254:
255: * and TTRAM. That is, you need 16MB/pagesize plus (tt_mbytes/pagesize)
256:
257: * bytes here.
258:
259: */
260:
261:
262:
263: unsigned char *global_mode_table;
264:
265:
266:
267: /*
268:
269: * prototype descriptors; field u1 must be all ones, other u? are zero.
270:
271: * This is just the first long of a full descriptor; the ".page_type" part
272:
273: * of the union. These are initialized by init_tables.
274:
275: *
276:
277: * The proto_page_type table yields the value to stuff into the page_type
278:
279: * field of a new process' page table. It is the "non-owner" mode for
280:
281: * a page with the corresponding value in global_mode_table.
282:
283: */
284:
285:
286:
287: page_type g_page;
288:
289: page_type g_ci_page;
290:
291: page_type s_page;
292:
293: page_type readable_page;
294:
295: page_type invalid_page;
296:
297: page_type page_ptr;
298:
299:
300:
1.1.1.2 root 301: page_type *const proto_page_type[] =
1.1 root 302:
303: { &invalid_page, &g_page, &s_page, &readable_page, &invalid_page };
304:
305: /* private global super private/read invalid */
306:
307:
308:
309: /*
310:
311: * Init_tables: called sometime in initialization. We set up some
312:
313: * constants here, but that's all. The first new_proc call will set up the
314:
315: * page table for the root process and switch it in; from then on, we're
316:
317: * always under some process' control.
318:
319: *
320:
321: * The master page-mode table is initialized here, and some constants like
322:
323: * the size needed for future page tables.
324:
325: *
326:
327: * One important constant initialized here is page_table_size, which is
328:
329: * the amount of memory required per page table. new_proc allocates
330:
331: * this much memory for each process' page table. This number will be
332:
333: * 1K/megabyte plus page table overhead. There are TBL_PAGES_OFFS
334:
335: * tables at TBL_SIZE_BYTES each before the main tables begin; then
336:
337: * there is 1024 bytes per megabyte of memory being mapped.
338:
339: */
340:
341:
342:
343: void
344:
345: init_tables()
346:
347: {
348:
349: int n_megabytes;
350:
351: long global_mode_table_size;
352:
353:
354:
355: if (no_mem_prot) return;
356:
357:
358:
359: TRACE(("init_tables"));
360:
361:
362:
363: #define phys_top_tt (*(ulong *)0x5a4L)
364:
365: if (phys_top_tt == 0x01000000L) mint_top_tt = 0;
366:
367: else mint_top_tt = phys_top_tt;
368:
369:
370:
371: #define phys_top_st (*(ulong *)0x42eL)
372:
373: mint_top_st = phys_top_st;
374:
375:
376:
377: if (mint_top_tt)
378:
379: tt_mbytes = (int) ((mint_top_tt - 0x01000000L) / ONE_MEG);
380:
381: else
382:
383: tt_mbytes = 0;
384:
385:
386:
387: n_megabytes = (int) ((mint_top_st / ONE_MEG) + tt_mbytes);
388:
389:
390:
391: /*
392:
393: * page table size: room for A table, B0 table, BF table, STRAM C
394:
395: * table, one TTRAM C table per 16MB (or fraction) of TTRAM, and 1024
396:
397: * bytes per megabyte.
398:
399: */
400:
401:
402:
403: page_table_size = (4L * TBL_SIZE_BYTES) +
404:
405: (((tt_mbytes+15L)/16L) * TBL_SIZE_BYTES) +
406:
407: (n_megabytes*1024L);
408:
409:
410:
411: global_mode_table_size = ((SIXTEEN_MEG / QUANTUM) +
412:
413: (((ulong)tt_mbytes * ONE_MEG) / QUANTUM));
414:
415:
416:
417: global_mode_table = kmalloc(global_mode_table_size);
418:
419:
420:
421: assert(global_mode_table);
422:
423:
424:
425: TRACELOW(("mint_top_st is $%lx; mint_top_tt is $%lx, n_megabytes is %d",
426:
427: mint_top_st, mint_top_tt, n_megabytes));
428:
429: TRACELOW(("page_table_size is %ld, global_mode_table_size %ld",
430:
431: page_table_size,
432:
433: global_mode_table_size));
434:
435:
436:
437: g_page.limit = 0x7fff; /* set nonzero fields: disabled limit */
438:
439: g_page.unused1 = 0x3f; /* ones in this reserved field */
440:
441: g_page.unused2 = 0;
442:
443: g_page.s = 0;
444:
445: g_page.unused3 = 0;
446:
447: g_page.ci = 0;
448:
449: g_page.unused4 = 0;
450:
451: g_page.m = 1; /* set m and u to 1 so CPU won't do writes */
452:
453: g_page.u = 1;
454:
455: g_page.wp = 0; /* not write-protected */
456:
457: g_page.dt = 1; /* descriptor type 1: page descriptor */
458:
459:
460:
461: g_ci_page = g_page;
462:
463: g_ci_page.ci = 1;
464:
465:
466:
467: readable_page = g_page; /* a page which is globally readable */
468:
469: readable_page.wp = 1; /* but write protected */
470:
471:
472:
473: s_page = g_page; /* a page which is globally accessible */
474:
475: s_page.s = 1; /* if you're supervisor */
476:
477:
478:
479: invalid_page = g_page;
480:
481: invalid_page.dt = 0;
482:
483:
484:
485: page_ptr = g_page;
486:
487: page_ptr.m = 0; /* this must be zero in page pointers */
488:
489: page_ptr.dt = 3;
490:
491:
492:
493: tc.enable = 1;
494:
495: tc.zeros = 0;
496:
497: tc.sre = 0;
498:
499: tc.fcl = 0;
500:
501: tc.is = 0;
502:
503: tc.tia = 4;
504:
505: tc.tib = 4;
506:
507: tc.tic = 4;
508:
509: tc.tid = 7; /* 0+4+4+4+7+13 == 32 */
510:
511: tc.ps = 13; /* 8K page size */
512:
513:
514:
515: /* set the whole global_mode_table to "global" */
516:
517: memset(global_mode_table,PROT_G,global_mode_table_size);
518:
519: }
520:
521:
522:
523: /*
524:
525: * mark_region: mark a region of memory as having a particular type.
526:
527: * The arguments are the memory region in question and the new type.
528:
529: * If the new type is zero then the old type is preserved. The
530:
531: * type of each page is kept in a global place for this purpose,
532:
533: * among others.
534:
535: *
536:
537: * The types are:
538:
539: * 0 private
540:
541: * 1 global
542:
543: * 2 private, but super-accessible
544:
545: * 3 private, but world readable
546:
547: * 4 invalid
548:
549: *
550:
551:
552:
553: The idea is this:
554:
555:
556:
557: for (each process) {
558:
559: if (you're an owner or you're special) {
560:
561: set up owner modes
562:
563: }
564:
565: else {
566:
567: set up non-owner modes
568:
569: }
570:
571:
572:
573: mark_pages(pagetbl,start,len,modes);
574:
575: }
576:
577:
578:
579: */
580:
581:
582:
583: /*
584:
1.1.1.2 root 585: invalid---v
1.1 root 586:
1.1.1.2 root 587: private/gr---v |
1.1 root 588:
1.1.1.2 root 589: super-------v | |
1.1 root 590:
1.1.1.2 root 591: global-------v | | |
1.1 root 592:
1.1.1.2 root 593: private-------v | | | |
1.1 root 594:
1.1.1.2 root 595: | | | | |
1.1 root 596:
597: */
598:
1.1.1.2 root 599: const ushort other_dt[] = { 0, 1, 1, 1, 0 };
1.1 root 600:
1.1.1.2 root 601: const ushort other_s[] = { 0, 0, 1, 0, 0 };
1.1 root 602:
1.1.1.2 root 603: const ushort other_wp[] = { 0, 0, 0, 1, 0 };
1.1 root 604:
605:
606:
607:
608:
609: /*
610:
611: * get_page_cookie: return a cookie representing the protection status
612:
613: * of some memory.
614:
615: *
616:
617: * Returns ((wp << 3) | (s << 2) | (dt) | 0x8000) when it wins.
618:
619: * Returns 1 if the pages are not all controlled, 0 if they're not all the same.
620:
621: */
622:
623:
624:
625: static short
626:
627: get_page_cookie(long_desc *base_tbl,ulong start,ulong len)
628:
629: {
630:
631: int b_index, c_index, d_index;
632:
1.1.1.3 ! root 633: long_desc *tbl, *tbl_b, *tbl_c;
1.1 root 634:
635: int dt, s, wp;
636:
637:
638:
639: if (start < mint_top_st) {
640:
641: /* start is in ST RAM; fail if not entirely in ST RAM */
642:
643: if (start+len > mint_top_st) {
644:
645: return 1;
646:
647: }
648:
649: }
650:
651: else if (start >= 0x01000000L && start < mint_top_tt) {
652:
653: /* start is in TT RAM; fail if not entirely in TT RAM */
654:
655: if (start+len > mint_top_tt) {
656:
657: return 1;
658:
659: }
660:
661: }
662:
663:
664:
1.1.1.3 ! root 665: /*
1.1 root 666:
1.1.1.3 ! root 667: * a_index is always zero. Only the first 256MB is mapped.
1.1 root 668:
1.1.1.3 ! root 669: * b_index is the 16MB number of the page.
1.1 root 670:
1.1.1.3 ! root 671: * c_index is the 1MB number of that page within the 16MB (0-15)
1.1 root 672:
1.1.1.3 ! root 673: * d_index is the 8K number within that 1MB (0-127).
1.1 root 674:
1.1.1.3 ! root 675: */
1.1 root 676:
677:
678:
1.1.1.3 ! root 679: b_index = (int)(start >> LOG2_16_MEG);
1.1 root 680:
1.1.1.3 ! root 681: c_index = (int)(start >> LOG2_ONE_MEG) & 0xf;
1.1 root 682:
1.1.1.3 ! root 683: d_index = (int)(start >> LOG2_EIGHT_K) & 0x7f;
1.1 root 684:
685:
686:
1.1.1.3 ! root 687: /* precompute the table addresses */
1.1 root 688:
1.1.1.3 ! root 689: tbl_b = &base_tbl[0].tbl_address[b_index];
1.1 root 690:
1.1.1.3 ! root 691: tbl_c = &tbl_b->tbl_address[c_index];
1.1 root 692:
1.1.1.3 ! root 693: tbl = &tbl_c->tbl_address[d_index];
1.1 root 694:
695:
696:
1.1.1.3 ! root 697: dt = tbl->page_type.dt;
1.1 root 698:
1.1.1.3 ! root 699: wp = tbl->page_type.wp;
! 700:
! 701: s = tbl->page_type.s;
1.1 root 702:
703:
704:
1.1.1.3 ! root 705: for (;;) {
1.1 root 706:
1.1.1.3 ! root 707: /* quickly loop through the 1MB-block */
1.1 root 708:
1.1.1.3 ! root 709: for (; len && tbl < &tbl_c->tbl_address[0x80]; tbl++)
1.1 root 710:
1.1.1.3 ! root 711: {
1.1 root 712:
1.1.1.3 ! root 713: if ((tbl->page_type.dt != dt) ||
1.1 root 714:
1.1.1.3 ! root 715: (tbl->page_type.s != s) ||
1.1 root 716:
1.1.1.3 ! root 717: (tbl->page_type.wp != wp)) {
1.1 root 718:
1.1.1.3 ! root 719: /* fail because it's not all the same protection */
1.1 root 720:
1.1.1.3 ! root 721: return 0;
1.1 root 722:
1.1.1.3 ! root 723: }
1.1 root 724:
1.1.1.3 ! root 725: len -= EIGHT_K;
1.1 root 726:
1.1.1.3 ! root 727: }
1.1 root 728:
729:
730:
1.1.1.3 ! root 731: if (len == 0L)
1.1 root 732:
1.1.1.3 ! root 733: break;
1.1 root 734:
735:
736:
1.1.1.3 ! root 737: /* step to the next d-table */
1.1 root 738:
1.1.1.3 ! root 739: tbl_c++;
1.1 root 740:
1.1.1.3 ! root 741: /* if crossing a 16MB boundary, get the next c-table */
1.1 root 742:
1.1.1.3 ! root 743: if (tbl_c == &tbl_b->tbl_address[0x10])
1.1 root 744:
1.1.1.3 ! root 745: {
1.1 root 746:
1.1.1.3 ! root 747: tbl_b++;
1.1 root 748:
1.1.1.3 ! root 749: tbl_c = tbl_b->tbl_address;
1.1 root 750:
1.1.1.3 ! root 751: }
1.1 root 752:
1.1.1.3 ! root 753: tbl = tbl_c->tbl_address;
1.1 root 754:
755: }
756:
757: /* we passed -- all the pages in question have the same prot. status */
758:
759: return (wp << 3) | (s << 2) | dt | 0x8000;
760:
761: }
762:
763:
764:
765: static void
766:
767: mark_pages(long_desc *base_tbl,ulong start,ulong len,
768:
769: ushort dt_val, ushort s_val, ushort wp_val, PROC *proc)
770:
771: {
772:
773: int b_index, c_index, d_index;
774:
1.1.1.3 ! root 775: long_desc *tbl, *tbl_b, *tbl_c;
1.1 root 776:
1.1.1.3 ! root 777: ulong oldlen;
1.1 root 778:
779:
780:
781: if (no_mem_prot) return;
782:
783:
784:
785: oldlen = len;
786:
787:
788:
789: /*
790:
1.1.1.3 ! root 791: * a_index is always zero. Only the first 256MB is mapped.
1.1 root 792:
1.1.1.3 ! root 793: * b_index is the 16MB number of the page.
1.1 root 794:
1.1.1.3 ! root 795: * c_index is the 1MB number of that page within the 16MB (0-15)
1.1 root 796:
1.1.1.3 ! root 797: * d_index is the 8K number within that 1MB (0-127).
1.1 root 798:
799: */
800:
801:
802:
803: b_index = (start >> LOG2_16_MEG);
804:
805: c_index = (start >> LOG2_ONE_MEG) & 0xf;
806:
807: d_index = (start >> LOG2_EIGHT_K) & 0x7f;
808:
809:
810:
1.1.1.3 ! root 811: /* precompute the table addresses */
! 812:
! 813: tbl_b = &base_tbl[0].tbl_address[b_index];
! 814:
! 815: tbl_c = &tbl_b->tbl_address[c_index];
! 816:
! 817: tbl = &tbl_c->tbl_address[d_index];
! 818:
! 819:
! 820:
! 821: #ifdef MEMPROT_SHORTCUT
! 822:
! 823: /*
! 824:
! 825: * Take a shortcut here: we're done if first page of the region is
! 826:
! 827: * already right.
1.1 root 828:
1.1.1.3 ! root 829: */
1.1 root 830:
1.1.1.3 ! root 831: /* I don't think this shortcut is a good idea, since while we
1.1 root 832:
1.1.1.3 ! root 833: * are doing Mshrink or Srealloc we may very well have a region
! 834:
! 835: * with mixed page types -- ERS
! 836:
! 837: */
1.1 root 838:
839:
840:
841: if (tbl->page_type.dt == dt_val &&
842:
843: tbl->page_type.s == s_val &&
844:
845: tbl->page_type.wp == wp_val) {
846:
847: /*
848:
849: TRACE(("mark_pages a:0 b:%d c:%d d:%d (same)",
850:
851: b_index,c_index,d_index));
852:
853: */
854:
855: return;
856:
857: }
858:
859:
860:
861: #endif /* MEMPROT_SHORTCUT */
862:
863: /*
864:
865: MP_DEBUG(("mark_pages a:0 b:%d c:%d d:%d (diff)",b_index,c_index,d_index));
866:
867: */
868:
869:
870:
1.1.1.3 ! root 871: for (;;)
1.1 root 872:
1.1.1.3 ! root 873: {
1.1 root 874:
1.1.1.3 ! root 875: /* quickly loop through the 1MB-block */
1.1 root 876:
1.1.1.3 ! root 877: for (; len && tbl < &tbl_c->tbl_address[0x80]; tbl++)
1.1 root 878:
1.1.1.3 ! root 879: {
1.1 root 880:
1.1.1.3 ! root 881: tbl->page_type.dt = dt_val;
1.1 root 882:
1.1.1.3 ! root 883: tbl->page_type.s = s_val;
1.1 root 884:
1.1.1.3 ! root 885: tbl->page_type.wp = wp_val;
1.1 root 886:
1.1.1.3 ! root 887: len -= EIGHT_K;
1.1 root 888:
1.1.1.3 ! root 889: }
1.1 root 890:
891:
892:
1.1.1.3 ! root 893: if (len == 0L)
1.1 root 894:
1.1.1.3 ! root 895: break;
1.1 root 896:
897:
898:
1.1.1.3 ! root 899: /* get the next d-table */
1.1 root 900:
1.1.1.3 ! root 901: tbl_c++;
1.1 root 902:
1.1.1.3 ! root 903: /* if crossing a 16MB boundary, get the next c-table */
1.1 root 904:
1.1.1.3 ! root 905: if (tbl_c == &tbl_b->tbl_address[0x10])
1.1 root 906:
1.1.1.3 ! root 907: {
1.1 root 908:
1.1.1.3 ! root 909: tbl_b++;
1.1 root 910:
1.1.1.3 ! root 911: tbl_c = tbl_b->tbl_address;
1.1 root 912:
1.1.1.3 ! root 913: }
1.1 root 914:
1.1.1.3 ! root 915: tbl = tbl_c->tbl_address;
1.1 root 916:
917: }
918:
919:
920:
1.1.1.2 root 921: flush_pmmu();
1.1 root 922:
1.1.1.2 root 923: if (mcpu <= 30) {
1.1 root 924:
1.1.1.2 root 925: /* On the '020 & '030 we have a logical cache, i.e. the DC & IC are on
1.1 root 926:
1.1.1.2 root 927: * the CPU side of the MMU, hence on an MMU context switch we must flush
1.1 root 928:
1.1.1.2 root 929: * them too. On the '040, by comparison, we have a physical cache, i.e.
1.1 root 930:
1.1.1.2 root 931: * the DC & IC are on the memory side of the MMU, so no DC/IC cache flush
1.1 root 932:
1.1.1.2 root 933: * is needed.
1.1 root 934:
1.1.1.2 root 935: */
1.1 root 936:
1.1.1.3 ! root 937: cpush((void *)start, oldlen);
1.1 root 938:
1.1.1.2 root 939: }
1.1 root 940:
941: }
942:
943:
944:
945: /* get_prot_mode(r): returns the type of protection region r
946:
947: * has
948:
949: */
950:
951:
952:
953: int
954:
955: get_prot_mode(r)
956:
957: MEMREGION *r;
958:
959: {
960:
961: ulong start = r->loc;
962:
963:
964:
965: if (no_mem_prot)
966:
967: return PROT_G;
968:
969: return global_mode_table[(start >> 13)];
970:
971: }
972:
973:
974:
975: void
976:
977: mark_region(region,mode)
978:
979: MEMREGION *region;
980:
981: short mode;
982:
983: {
984:
985: ulong start = region->loc;
986:
987: ulong len = region->len;
988:
989: ulong i;
990:
991: ushort dt_val, s_val, wp_val;
992:
993: PROC *proc;
994:
995: MEMREGION **mr;
996:
997:
998:
999: if (no_mem_prot) return;
1000:
1001:
1002:
1003: MP_DEBUG(("mark_region %lx len %lx mode %d",start,len,mode));
1004:
1005:
1006:
1.1.1.3 ! root 1007: #if 0 /* this should not occur any more */
! 1008:
1.1 root 1009: if (mode == PROT_NOCHANGE) {
1010:
1011: mode = global_mode_table[(start >> 13)];
1012:
1013: }
1014:
1.1.1.3 ! root 1015: #else
! 1016:
! 1017: assert(mode != PROT_NOCHANGE);
! 1018:
! 1019: #endif
! 1020:
1.1 root 1021:
1022:
1023: /* mark the global page table */
1024:
1025:
1026:
1027: memset(&global_mode_table[start >> 13],mode,(len >> 13));
1028:
1029:
1030:
1031: for (proc = proclist; proc; proc = proc->gl_next) {
1032:
1033: assert(proc->page_table);
1034:
1035: if (mode == PROT_I || mode == PROT_G) {
1036:
1037: /* everybody gets the same flags */
1038:
1039: goto notowner;
1040:
1041: }
1042:
1043: if (proc->memflags & F_OS_SPECIAL) {
1044:
1045: /* you're special; you get owner flags */
1046:
1047: MP_DEBUG(("mark_region: pid %d is an OS special!",proc->pid));
1048:
1049: goto owner;
1050:
1051: }
1052:
1.1.1.2 root 1053: if ((mr = proc->mem) != 0) {
1.1 root 1054:
1055: for (i = 0; i < proc->num_reg; i++, mr++) {
1056:
1057: if (*mr == region) {
1058:
1059: MP_DEBUG(("mark_region: pid %d is an owner",proc->pid));
1060:
1061: owner:
1062:
1063: dt_val = 1;
1064:
1065: s_val = 0;
1066:
1067: wp_val = 0;
1068:
1069: goto gotvals;
1070:
1071: }
1072:
1073: }
1074:
1075: }
1076:
1077:
1078:
1079: notowner:
1080:
1081:
1082:
1083: /* if you get here you're not an owner, or mode is G or I */
1084:
1085: MP_DEBUG(("mark_region: pid %d gets non-owner modes",proc->pid));
1086:
1087:
1088:
1089: dt_val = other_dt[mode];
1090:
1091: s_val = other_s[mode];
1092:
1093: wp_val = other_wp[mode];
1094:
1095:
1096:
1097: gotvals:
1098:
1099: mark_pages(proc->page_table,start,len,dt_val,s_val,wp_val,proc);
1100:
1101: }
1102:
1103: }
1104:
1105:
1106:
1.1.1.3 ! root 1107: /* special version of mark_region, used for attaching (mode == PROT_P)
! 1108:
! 1109: and detaching (mode == PROT_I) a memory region to/from a process. */
! 1110:
! 1111: void
! 1112:
! 1113: mark_proc_region(proc,region,mode)
! 1114:
! 1115: PROC *proc;
! 1116:
! 1117: MEMREGION *region;
! 1118:
! 1119: short mode;
! 1120:
! 1121: {
! 1122:
! 1123: ulong start = region->loc;
! 1124:
! 1125: ulong len = region->len;
! 1126:
! 1127: ushort dt_val, s_val, wp_val;
! 1128:
! 1129: short global_mode;
! 1130:
! 1131:
! 1132:
! 1133: if (no_mem_prot) return;
! 1134:
! 1135:
! 1136:
! 1137: MP_DEBUG(("mark_region %lx len %lx mode %d for pid %d",
! 1138:
! 1139: start, len, mode, proc->pid));
! 1140:
! 1141:
! 1142:
! 1143: global_mode = global_mode_table[(start >> 13)];
! 1144:
! 1145:
! 1146:
! 1147: assert(proc->page_table);
! 1148:
! 1149: if (global_mode == PROT_I || global_mode == PROT_G)
! 1150:
! 1151: mode = global_mode;
! 1152:
! 1153: else {
! 1154:
! 1155: if (proc->memflags & F_OS_SPECIAL) {
! 1156:
! 1157: /* you're special; you get owner flags */
! 1158:
! 1159: MP_DEBUG(("mark_region: pid %d is an OS special!",proc->pid));
! 1160:
! 1161: goto owner;
! 1162:
! 1163: }
! 1164:
! 1165: if (mode == PROT_P) {
! 1166:
! 1167: MP_DEBUG(("mark_region: pid %d is an owner",proc->pid));
! 1168:
! 1169: owner:
! 1170:
! 1171: dt_val = 1;
! 1172:
! 1173: s_val = 0;
! 1174:
! 1175: wp_val = 0;
! 1176:
! 1177: goto gotvals;
! 1178:
! 1179: }
! 1180:
! 1181: }
! 1182:
! 1183:
! 1184:
! 1185: /* if you get here you're not an owner, or mode is G or I */
! 1186:
! 1187: MP_DEBUG(("mark_region: pid %d gets non-owner modes",proc->pid));
! 1188:
! 1189:
! 1190:
! 1191: dt_val = other_dt[mode];
! 1192:
! 1193: s_val = other_s[mode];
! 1194:
! 1195: wp_val = other_wp[mode];
! 1196:
! 1197:
! 1198:
! 1199: gotvals:
! 1200:
! 1201: mark_pages(proc->page_table,start,len,dt_val,s_val,wp_val,proc);
! 1202:
! 1203: }
! 1204:
! 1205:
! 1206:
1.1 root 1207: /*
1208:
1209: * prot_temp: temporarily alter curproc's access to memory.
1210:
1211: * Pass in a -1 to give curproc global access; returns a cookie. Call
1212:
1213: * again with that cookie to return the memory to the old mode.
1214:
1215: * There should be no context switches or memory protection changes
1216:
1217: * in the meantime.
1218:
1219: *
1220:
1221: * If called with mode == -1, returns...
1222:
1223: * -1 if mem prot is off -- no error, no action.
1224:
1225: * 0 if the pages are not all the same.
1226:
1227: * 1 if the pages are not all controlled by the page tables.
1228:
1229: *
1230:
1231: * When mode != -1, returns...
1232:
1233: * 0 for success (should never fail). There is little checking.
1234:
1235: * Calling with mode == 0 or 1 results in zero to spoof success, but in fact
1236:
1237: * this is an error. Mode is only really valid if (mode & 0x8000).
1238:
1239: */
1240:
1241:
1242:
1243: int
1244:
1245: prot_temp(loc,len,mode)
1246:
1247: ulong loc;
1248:
1249: ulong len;
1250:
1251: int mode;
1252:
1253: {
1254:
1255: int cookie;
1256:
1257:
1258:
1259: if (no_mem_prot) return -1;
1260:
1261:
1262:
1263: /* round start down to the previous page and len up to the next one. */
1264:
1.1.1.3 ! root 1265: len += loc & MASKBITS;
! 1266:
1.1 root 1267: loc &= ~MASKBITS;
1268:
1269: len = ROUND(len);
1270:
1271:
1272:
1273: if (mode == 0 || mode == 1) return 0; /* do nothing */
1274:
1275: if (mode == -1) {
1276:
1277: cookie = get_page_cookie(curproc->page_table,loc,len);
1278:
1279:
1280:
1281: /* if not all controlled, return status */
1282:
1283: if (cookie == 0 || cookie == 1) return cookie;
1284:
1285:
1286:
1287: mark_pages(curproc->page_table,loc,len,1,0,0,curproc);
1288:
1289:
1290:
1291: return cookie;
1292:
1293: }
1294:
1295: else {
1296:
1297: mark_pages(curproc->page_table,loc,len,
1298:
1.1.1.2 root 1299: mode&3,(mode&4)>>2,(mode&8)>>3,curproc);
1.1 root 1300:
1301: return 0;
1302:
1303: }
1304:
1305: }
1306:
1307:
1308:
1309: /*
1310:
1311: * init_page_table: fill in the page table for the indicated process. The
1312:
1313: * master page map is consulted for the modes of all pages, and the memory
1314:
1315: * region data structures are consulted to see if this process is the owner
1316:
1317: * of any of those tables.
1318:
1319: *
1320:
1321: * This also sets crp and tc in both ctxts of the process. If this is the
1322:
1323: * first call, then the CPU tc is cleared, the TT0 and TT1 regs are zapped,
1324:
1325: * and then this proc's crp and tc are loaded into it.
1326:
1327: */
1328:
1329:
1330:
1331: static short mmu_is_set_up = 0;
1332:
1333:
1334:
1335: void
1336:
1337: init_page_table(proc)
1338:
1339: PROC *proc;
1340:
1341: {
1342:
1343: long_desc *tptr;
1344:
1345: long_desc *tbl_a; /* top-level table */
1346:
1347: long_desc *tbl_b0; /* second level, handles $0 nybble */
1348:
1349: long_desc *tbl_bf; /* handles $F nybble */
1350:
1351: long_desc *tbl_c; /* temp pointer to start of 16MB */
1352:
1353: ulong p, q, r;
1354:
1355: ulong i, j, k;
1356:
1357: int g;
1358:
1359: MEMREGION **mr;
1360:
1361:
1362:
1363: if (no_mem_prot) return;
1364:
1365:
1366:
1.1.1.3 ! root 1367: assert(proc && proc->page_table);
1.1 root 1368:
1369:
1370:
1.1.1.3 ! root 1371: if (proc->pid)
1.1 root 1372:
1.1.1.3 ! root 1373: TRACELOW(("init_page_table(proc=%lx, pid %d)",proc,proc->pid));
1.1 root 1374:
1375:
1376:
1377: tptr = proc->page_table;
1378:
1379: tbl_a = tptr;
1380:
1381: tptr += TBL_SIZE;
1382:
1383: tbl_b0 = tptr;
1384:
1385: tptr += TBL_SIZE;
1386:
1387: tbl_bf = tptr;
1388:
1389: tptr += TBL_SIZE;
1390:
1391:
1392:
1393: /*
1394:
1395: * table A indexes by the first nybble: $0 and $F refer to their tables,
1396:
1397: * $1-$7 are uncontrolled, cacheable; $8-$E are uncontrolled, ci.
1398:
1399: */
1400:
1401:
1402:
1403: tbl_a[0].page_type = page_ptr;
1404:
1405: tbl_a[0].tbl_address = tbl_b0;
1406:
1407:
1408:
1409: for (i=1; i<0xf; i++) {
1410:
1411: if (i < 8) tbl_a[i].page_type = g_page;
1412:
1413: else tbl_a[i].page_type = g_ci_page;
1414:
1415: tbl_a[i].tbl_address = (long_desc *)(i << 28);
1416:
1417: }
1418:
1419:
1420:
1421: /* $F entry of table A refers to table BF */
1422:
1423: tbl_a[0xf].page_type = page_ptr;
1424:
1425: tbl_a[0xf].tbl_address = tbl_bf;
1426:
1427:
1428:
1429: /*
1430:
1431: * table B0: entry 0 is $00, the 16MB of ST address space.
1432:
1433: */
1434:
1435:
1436:
1437: tbl_b0[0].page_type = page_ptr;
1438:
1439: tbl_b0[0].tbl_address = tptr;
1440:
1441: tbl_c = tptr;
1442:
1443: tptr += TBL_SIZE;
1444:
1445:
1446:
1447: /* for each megabyte that is RAM, allocate a table */
1448:
1449: for (i = 0, k = 0, p = 0; p < mint_top_st; i++, p += 0x00100000L) {
1450:
1451: tbl_c[i].page_type = page_ptr;
1452:
1453: tbl_c[i].tbl_address = tptr;
1454:
1455:
1456:
1457: /* for each page in this megabyte, write a page entry */
1458:
1459: for (q = p, j = 0; j < 128; j++, q += 0x2000, k++) {
1460:
1461: tptr->page_type = *proto_page_type[global_mode_table[k]];
1462:
1463: tptr->tbl_address = (long_desc *)q;
1464:
1465: tptr++;
1466:
1467: }
1468:
1469: }
1470:
1471:
1472:
1473: /* now for each megabyte from mint_top_st to ROM, mark global */
1474:
1475: for ( ; p < 0x00E00000L; i++, p += 0x00100000L) {
1476:
1477: tbl_c[i].page_type = g_page;
1478:
1479: tbl_c[i].tbl_address = (long_desc *)p;
1480:
1481: }
1482:
1483:
1484:
1485: /* fill in the E and F tables: 00Ex is ROM, 00Fx is I/O */
1486:
1487: tbl_c[i].page_type = g_page;
1488:
1489: tbl_c[i].tbl_address = (long_desc *)p;
1490:
1491: i++, p += 0x00100000L;
1492:
1493: tbl_c[i].page_type = g_ci_page;
1494:
1495: tbl_c[i].tbl_address = (long_desc *)p;
1496:
1497:
1498:
1499: /* Done with tbl_c for 0th 16MB; go on to TT RAM */
1500:
1501:
1502:
1503: /*
1504:
1505: structure:
1506:
1507:
1508:
1509: for (i = each 16MB that has any TT RAM in it)
1510:
1511: allocate a table tbl_c, point tbl_b0[i] at it
1512:
1513: for (j = each 1MB that is RAM)
1514:
1515: allocate a table, point tbl_c[j] at it
1516:
1517: for (k = each page in the megabyte)
1518:
1519: fill in tbl_c[j][k] with page entry from global_mode_table
1520:
1521: for (j = the rest of the 16MB)
1522:
1523: set tbl_c[j] to "global, cacheable"
1524:
1525:
1526:
1527: for (i = the rest of the 16MBs from here to $7F)
1528:
1529: set tbl_b0[i] to "global, cacheable"
1530:
1531:
1532:
1533: for (i = the rest of the 16MBs from $80 up to but not incl. $FF)
1534:
1535: set tbl_b0[i] to "global, not cacheable"
1536:
1537: */
1538:
1539:
1540:
1541: /* i counts 16MBs */
1542:
1543: for (i = 1, p = 0x01000000L, g = 2048;
1544:
1545: p < mint_top_tt;
1546:
1547: p += SIXTEEN_MEG, i++) {
1548:
1549: tbl_b0[i].page_type = page_ptr;
1550:
1551: tbl_b0[i].tbl_address = tptr;
1552:
1553: tbl_c = tptr;
1554:
1555: tptr += TBL_SIZE;
1556:
1557:
1558:
1559: /* j counts MBs */
1560:
1561: for (j = 0, q = p; j < 16 && q < mint_top_tt; q += ONE_MEG, j++) {
1562:
1563: tbl_c[j].page_type = page_ptr;
1564:
1565: tbl_c[j].tbl_address = tptr;
1566:
1567: /* k counts pages (8K) */
1568:
1569: for (r = q, k = 0; k < 128; k++, r += 0x2000, g++) {
1570:
1571: tptr->page_type = *proto_page_type[global_mode_table[g]];
1572:
1573: tptr->tbl_address = (long_desc *)r;
1574:
1575: tptr++;
1576:
1577: }
1578:
1579: }
1580:
1581: for ( ; j < 16; j++, q += ONE_MEG) {
1582:
1583: /* fill in the rest of this 16MB */
1584:
1585: tbl_c[j].page_type = g_page;
1586:
1587: tbl_c[j].tbl_address = (long_desc *)q;
1588:
1589: }
1590:
1591: }
1592:
1593:
1594:
1595: /* fill in the rest of $00-$0F as cacheable */
1596:
1597: for ( ; i < 16; i++, p += SIXTEEN_MEG) {
1598:
1599: tbl_b0[i].page_type = g_page;
1600:
1601: tbl_b0[i].tbl_address = (long_desc *)p;
1602:
1603: }
1604:
1605:
1606:
1607: /* done with TT RAM in table b0; do table bf */
1608:
1609:
1610:
1611: /*
1612:
1613: * Table BF: translates addresses starting with $F. First 15 are
1614:
1615: * uncontrolled, cacheable; last one translates $FF, which
1616:
1617: * which shadows $00 (the 16MB ST address space). The rest
1618:
1619: * are uncontrolled, not cacheable.
1620:
1621: *
1622:
1623: * The table address of the copy has a 1 in the low (unused) bit, which
1624:
1625: * is a signal to the table dumper not to dump this, as it's a copy
1626:
1627: * of tbl_b0[0].
1628:
1629: */
1630:
1631:
1632:
1633: for (i=0; i<0xf; i++) {
1634:
1635: tbl_bf[i].page_type = g_ci_page;
1636:
1637: tbl_bf[i].tbl_address = (long_desc *)((i << 24) | 0xf0000000L);
1638:
1639: }
1640:
1641: tbl_bf[0xf] = tbl_b0[0];
1642:
1643: *(ulong *)(&(tbl_bf[0xf].tbl_address)) |= 1;
1644:
1645:
1646:
1647: proc->ctxt[0].crp.limit = 0x7fff; /* disable limit function */
1648:
1649: proc->ctxt[0].crp.dt = 3; /* points to valid 8-byte entries */
1650:
1651: proc->ctxt[0].crp.tbl_address = tbl_a;
1652:
1653: proc->ctxt[1].crp = proc->ctxt[0].crp;
1654:
1655: proc->ctxt[0].tc = tc;
1656:
1657: proc->ctxt[1].tc = tc;
1658:
1659:
1660:
1661: /*
1662:
1663: * OK, memory tables are now there as if you're a non-owner of every
1664:
1665: * page. Now for each region you ARE an owner of, mark with owner
1666:
1667: * modes.
1668:
1669: */
1670:
1671:
1672:
1673: mr = proc->mem;
1674:
1675: for (i=0; i < proc->num_reg; i++, mr++) {
1676:
1677: if (*mr) {
1678:
1679: mark_pages(proc->page_table,(*mr)->loc,(*mr)->len,1,0,0,proc);
1680:
1681: }
1682:
1683: }
1684:
1685:
1686:
1687: if (!mmu_is_set_up) {
1688:
1689: set_mmu(proc->ctxt[0].crp,proc->ctxt[0].tc);
1690:
1691: mmu_is_set_up = 1;
1692:
1693: }
1694:
1695: }
1696:
1697:
1698:
1699: /*
1700:
1701: * This routine is called when procfs detects that a process wants to be an
1702:
1703: * OS SPECIAL. The AES, SCRENMGR, and DESKTOP do this, and so does FSMGDOS
1704:
1705: * and possibly some other stuff. It has to re-mark every page in that
1706:
1707: * process' page table based on its new special status. The "special
1708:
1709: * status" is "you get global access to all of memory" and "everybody
1710:
1711: * gets Super access to yours." It is the caller's responsibility
1712:
1713: * to set proc's memflags, usually to (F_OS_SPECIAL | F_PROT_S).
1714:
1715: */
1716:
1717:
1718:
1719: void
1720:
1721: mem_prot_special(proc)
1722:
1723: PROC *proc;
1724:
1725: {
1726:
1727: MEMREGION **mr;
1728:
1729: int i;
1730:
1731:
1732:
1733: if (no_mem_prot) return;
1734:
1735:
1736:
1737: TRACE(("mem_prot_special(pid %d)",proc->pid));
1738:
1739:
1740:
1741: /*
1742:
1743: * This marks ALL memory, allocated or not, as accessible. When memory
1744:
1745: * is freed even F_OS_SPECIAL processes lose access to it. So one or
1746:
1747: * the other of these is a bug, depending on how you want it to work.
1748:
1749: */
1750:
1751: mark_pages(proc->page_table,0,mint_top_st,1,0,0,proc);
1752:
1753: if (mint_top_tt) {
1754:
1755: mark_pages(proc->page_table,
1756:
1757: 0x01000000L,
1758:
1759: mint_top_tt - 0x01000000L,
1760:
1761: 1,0,0,
1762:
1763: proc);
1764:
1765: }
1766:
1767:
1768:
1769: /*
1770:
1771: * In addition, mark all the pages the process already owns as "super"
1772:
1773: * in all other processes. Thus the "special" process can access all
1774:
1775: * of memory, and any process can access the "special" process' memory
1776:
1777: * when in super mode.
1778:
1779: */
1780:
1781:
1782:
1783: mr = proc->mem;
1784:
1785:
1786:
1787: for (i=0; i < proc->num_reg; i++, mr++) {
1788:
1789: if (*mr) {
1790:
1791: mark_region(*mr,PROT_S);
1792:
1793: }
1794:
1795: }
1796:
1797: }
1798:
1799:
1800:
1801: /*----------------------------------------------------------------------------
1802:
1803: * DEBUGGING SECTION
1804:
1805: *--------------------------------------------------------------------------*/
1806:
1807:
1808:
1809: static void
1810:
1811: _dump_tree(tbl,level)
1812:
1813: long_desc tbl;
1814:
1815: int level;
1816:
1817: {
1818:
1819: int i, j;
1820:
1821: long_desc *p;
1822:
1.1.1.2 root 1823: static const char spaces[9] = " ";
1.1 root 1824:
1825:
1826:
1827: /* print the level and display the table descriptor */
1828:
1829: FORCE("\r%s s:%x wp:%x dt:%x a:%08lx",
1830:
1831: &spaces[8-(level*2)],
1832:
1833: tbl.page_type.s,
1834:
1835: tbl.page_type.wp,
1836:
1837: tbl.page_type.dt,
1838:
1839: tbl.tbl_address);
1840:
1841:
1842:
1843: if (tbl.page_type.dt == 3) {
1844:
1845: if (level == 0) {
1846:
1847: j = (1 << tc.tia);
1848:
1849: }
1850:
1851: else if (level == 1) {
1852:
1853: j = (1 << tc.tib);
1854:
1855: }
1856:
1857: else if (level == 2) {
1858:
1859: j = (1 << tc.tic);
1860:
1861: }
1862:
1863: else {
1864:
1865: j = (1 << tc.tid);
1866:
1867: }
1868:
1869:
1870:
1871: /* don't show table if it's the duplicate */
1872:
1873: if ((ulong)tbl.tbl_address & 1) return;
1874:
1875:
1876:
1877: ++level;
1878:
1879: p = tbl.tbl_address;
1880:
1881: for (i=0; i<j; i++, p++) {
1882:
1883: _dump_tree(*p,level);
1884:
1885: }
1886:
1887: }
1888:
1889: }
1890:
1891:
1892:
1.1.1.2 root 1893: static const char modesym[] = { 'p', 'g', 's', 'r', 'i' };
1.1 root 1894:
1895:
1896:
1897: void
1898:
1899: QUICKDUMP()
1900:
1901: {
1902:
1903: char outstr[33];
1904:
1905: ulong i, j, end;
1906:
1907:
1908:
1909: if (no_mem_prot) return;
1910:
1911:
1912:
1913: FORCE("STRAM global table:");
1914:
1915: outstr[32] = '\0';
1916:
1917: end = mint_top_st / QUANTUM;
1918:
1919: for (i = 0; i < end; i += 32) {
1920:
1921: for (j=0; j<32; j++) {
1922:
1923: outstr[j] = modesym[global_mode_table[j+i]];
1924:
1925: }
1926:
1927: FORCE("%08lx: %s",i*8192L,outstr);
1928:
1929: }
1930:
1931:
1932:
1933: if (mint_top_tt) {
1934:
1935: FORCE("TTRAM global table:");
1936:
1937: end = mint_top_tt / QUANTUM;
1938:
1939: for (i = 2048; i < end; i += 32) {
1940:
1941: for (j=0; j<32; j++) {
1942:
1943: outstr[j] = modesym[global_mode_table[j+i]];
1944:
1945: }
1946:
1947: FORCE("%08lx: %s",i*8192L,outstr);
1948:
1949: }
1950:
1951: }
1952:
1953: }
1954:
1955:
1956:
1957: const char *berr_msg[] = {
1958:
1959: /* "........." */
1960:
1961: "private ",
1962:
1963: "global ", /* turned into "hardware" for violation reports */
1964:
1965: "super ",
1966:
1967: "readable ",
1968:
1969: "free ",
1970:
1971: "hardware " /* used when the memory is not controlled by us */
1972:
1973: };
1974:
1975:
1976:
1977: void
1978:
1979: report_buserr()
1980:
1981: {
1982:
1.1.1.2 root 1983: const char *vmsg;
1.1 root 1984:
1985: short mode;
1986:
1987: ulong aa, pc;
1988:
1989: char alertbuf[5*32+16]; /* enough for an alert */
1990:
1991: char *aptr;
1992:
1993:
1994:
1995: if (no_mem_prot) return;
1996:
1997:
1998:
1999: aa = curproc->exception_addr;
2000:
2001: pc = curproc->exception_pc;
2002:
2003: if ((mint_top_tt && aa < mint_top_tt) || (aa < mint_top_st)) {
2004:
2005: mode = global_mode_table[(curproc->exception_addr >> 13)];
2006:
2007: if (mode == PROT_G) {
2008:
2009: /* page is global: obviously a hardware bus error */
2010:
2011: mode = 5;
2012:
2013: }
2014:
2015: }
2016:
2017: else {
2018:
2019: /* (addr is > mint_top_tt) set mode = 5 so we don't look for owners */
2020:
2021: mode = 5;
2022:
2023: }
2024:
2025: vmsg = berr_msg[mode];
2026:
2027:
2028:
2029: /* construct an AES alert box for this error:
2030:
2031: | PROCESS "buserrxx" KILLED: |
2032:
2033: | MEMORY VIOLATION. (PID 000) |
2034:
2035: | |
2036:
2037: | Type: ......... PC: pc...... |
2038:
2039: | Addr: ........ BP: ........ |
2040:
2041: */
2042:
2043:
2044:
2045: /* we play games to get around 128-char max for ksprintf */
2046:
2047: ksprintf(alertbuf,"[1][ PROCESS \"%s\" KILLED: |",curproc->name);
2048:
2049: aptr = alertbuf + strlen(alertbuf);
2050:
2051: ksprintf(aptr," MEMORY VIOLATION. (PID %03d) | |",curproc->pid);
2052:
2053: aptr = alertbuf + strlen(alertbuf);
2054:
2055: ksprintf(aptr," Type: %s PC: %08lx |",vmsg,pc);
2056:
2057: aptr = alertbuf + strlen(alertbuf);
2058:
2059: ksprintf(aptr," Addr: %08lx BP: %08lx ][ OK ]",aa,curproc->base);
2060:
2061: if (!_ALERT(alertbuf)) {
2062:
2063: /* this will call _alert again, but it will just fail again */
2064:
2065: ALERT("MEMORY VIOLATION: type=%s AA=%lx PC=%lx BP=%lx",
2066:
2067: vmsg,aa,pc,curproc->base);
2068:
2069: }
2070:
2071:
2072:
2073: if (curproc->pid == 0 || curproc->memflags & F_OS_SPECIAL) {
2074:
2075: /* the system is so thoroughly hosed that anything we try will
2076:
2077: * likely cause another bus error; so let's just hang up
2078:
2079: */
2080:
2081: FATAL("Operating system killed");
2082:
2083: }
2084:
2085: }
2086:
2087:
2088:
2089: /*
2090:
2091: * big_mem_dump is a biggie: for each page in the system, it
2092:
2093: * displays the PID of the (first) owner and the protection mode.
2094:
2095: * The output has three chars per page, and eight chars per line.
2096:
2097: * The first page of a region is marked with the mode, and the
2098:
2099: * rest with a space.
2100:
2101: *
2102:
2103: * Logic:
2104:
2105: for (mp = *core; mp; mp++) {
2106:
2107: for (each page of this region) {
2108:
2109: if (start of line) {
2110:
2111: output line starter;
2112:
2113: }
2114:
2115: if (start of region) {
2116:
2117: output mode of this page;
2118:
2119: determine owner;
2120:
2121: output owner;
2122:
2123: }
2124:
2125: else {
2126:
2127: output space;
2128:
2129: output owner;
2130:
2131: }
2132:
2133: }
2134:
2135: }
2136:
2137: */
2138:
2139:
2140:
2141: void
2142:
2143: BIG_MEM_DUMP(bigone,proc)
2144:
2145: int bigone;
2146:
2147: PROC *proc;
2148:
2149: {
2150:
1.1.1.2 root 2151: #ifdef DEBUG_INFO
1.1 root 2152:
2153: char linebuf[128];
2154:
2155: char *lp = linebuf;
2156:
2157: MEMREGION *mp, **mr, **map;
2158:
2159: PROC *p;
2160:
2161: ulong loc;
2162:
1.1.1.2 root 2163: short owner;
1.1 root 2164:
2165: short i;
2166:
2167: short first;
2168:
2169:
2170:
2171:
2172:
2173: if (no_mem_prot) return;
2174:
2175:
2176:
2177: for (map = core; map != 0; ((map == core) ? (map = alt) : (map = 0))) {
2178:
2179: FORCE("Annotated memory dump for %s",(map == core ? "core" : "alt"));
2180:
2181: first = 1;
2182:
2183: *linebuf = '\0';
2184:
2185: for (mp = *map; mp; mp = mp->next) {
2186:
2187: for (loc = mp->loc; loc < (mp->loc + mp->len); loc += EIGHT_K) {
2188:
2189: if (first || ((loc & 0x1ffff) == 0)) {
2190:
2191: if (*linebuf) FORCE(linebuf);
2192:
2193: ksprintf(linebuf,"\r%08lx: ",loc);
2194:
2195: lp = &linebuf[11];
2196:
2197: first = 0;
2198:
2199: }
2200:
2201: if (loc == mp->loc) {
2202:
2203: *lp++ = modesym[global_mode_table[loc / EIGHT_K]];
2204:
2205:
2206:
2207: for (p = proclist; p; p = p->gl_next) {
2208:
2209: if (p->mem) {
2210:
2211: mr = p->mem;
2212:
2213: for (i=0; i < p->num_reg; i++, mr++) {
2214:
2215: if (*mr == mp) {
2216:
2217: owner = p->pid;
2218:
2219: goto gotowner;
2220:
2221: }
2222:
2223: }
2224:
2225: }
2226:
2227: }
2228:
2229: owner = 000;
2230:
2231: gotowner:
2232:
2233: ksprintf(lp,"%03d",owner);
2234:
2235: lp += 3;
2236:
2237: }
2238:
2239: else {
2240:
2241: *lp++ = ' ';
2242:
2243: *lp++ = '-';
2244:
2245: *lp++ = '-';
2246:
2247: *lp++ = '-';
2248:
2249: *lp = '\0'; /* string is always null-terminated */
2250:
2251: }
2252:
2253: }
2254:
2255: }
2256:
2257: FORCE(linebuf);
2258:
2259: }
2260:
2261:
2262:
2263: if (bigone) {
2264:
2265: long_desc tbl;
2266:
2267:
2268:
2269: /* fill in tbl with the only parts used at the top level */
2270:
2271: tbl.page_type.dt = proc->ctxt[CURRENT].crp.dt;
2272:
2273: tbl.tbl_address = proc->ctxt[CURRENT].crp.tbl_address;
2274:
2275: _dump_tree(tbl,0);
2276:
2277: }
2278:
1.1.1.2 root 2279: #endif /* DEBUG_INFO */
1.1 root 2280:
2281: }
2282:
2283:
2284:
2285:
2286:
2287: /*
2288:
2289: * Can the process "p" access the "nbytes" long
2290:
2291: * block of memory starting at "start"?
2292:
2293: * If it would be a legal access, the current
2294:
2295: * process is given temporary access via
2296:
2297: * prot_temp.
2298:
2299: * Returns a cookie like the one prot_temp
2300:
2301: * returns; if the process shouldn't have
2302:
2303: * access to the memory, returns 1.
2304:
2305: *
2306:
2307: * BUG: should actually read p's page table to
2308:
2309: * determine access
2310:
2311: */
2312:
2313:
2314:
2315: int
2316:
2317: mem_access_for(p, start, nbytes)
2318:
2319: PROC *p;
2320:
2321: ulong start;
2322:
2323: long nbytes;
2324:
2325: {
2326:
2327: MEMREGION **mr;
2328:
2329: int i;
2330:
2331:
2332:
2333: if (no_mem_prot) return -1;
2334:
2335: if (start >= (ulong)p && start+nbytes <= (ulong)(p+1))
2336:
2337: return -1;
2338:
2339: if (p == rootproc)
2340:
2341: goto win_and_mark;
2342:
2343:
2344:
2345: mr = p->mem;
2346:
2347: if (mr) {
2348:
2349: for (i = 0; i < p->num_reg; i++, mr++) {
2350:
2351: if (*mr) {
2352:
2353: if (((*mr)->loc <= start) &&
2354:
2355: ((*mr)->loc + (*mr)->len >= start + nbytes))
2356:
2357: goto win_and_mark;
2358:
2359: }
2360:
2361: }
2362:
2363: }
2364:
2365:
2366:
2367: return 0; /* we don't own this memory */
2368:
2369:
2370:
2371: win_and_mark:
2372:
2373: return prot_temp(start, nbytes, -1);
2374:
2375: }
2376:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.