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