home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 581b.lha / showmmu_v1.0 / showmmu.c < prev    next >
C/C++ Source or Header  |  1991-10-08  |  14KB  |  464 lines

  1. ;/* this is how to compile this program in a gcc(2.0)-environment 
  2.  
  3. ;   this trick enables us to generate 68020 code, but the very start of the 
  4. ;   program runs on a 68000 as well. -mc68000 inhibits gas' jsr->bsr
  5. ;   transformation at the cost of generating lots more reloc32 than necessary
  6. gcc2 -O2 -S -mc68020 showmmu.c
  7. gcc2 -mc68000 showmmu.s -o showmmu
  8. quit
  9. */
  10.  
  11. /*
  12.  * Dump the current MMU table and show the various MMU status flags (except
  13.  * the status-register itself, which isn't really useful if not doing explicit
  14.  * address translation).
  15.  * If you want to learn about how the MMU works, I strongly recommend you
  16.  * read either the 68851 or the 68030 user manual, they explain `everything'
  17.  * you want to know, and more ;-)
  18.  * This program has been written for a 68030 MMU, it doesn't support 68851-only
  19.  * features, since I can't test them, and I don't need them ;-)
  20.  * This program is my first attempt at understanding how `my' MMU works, and
  21.  * I guess I know enough now to try to write my own tables;-)
  22.  *
  23.  * V1.0  91-10-7  M. Wild  first hack (it's a one-session hack I admit ;-))
  24.  *                Bugs: o  No indirect page-descriptors. If they're used,
  25.  *                         they're translated as table-descriptors, with quite
  26.  *                         possibly a deadly (hi guru;-)) result
  27.  *                      o  No checks for too deeply nested tables (same applies
  28.  *                         as above). This is not too bad, since only active
  29.  *               page tables are dumped, they already have proven to
  30.  *               be somewhat sensible...
  31.  *                      o  No support for function codes. Same scenario to be
  32.  *                         expected as in the above cases...
  33.  *
  34.  * This is free software. This means that I don't care what you do with it
  35.  * as long as you don't claim you wrote it. If you enhance it, please
  36.  * send me your diffs! 
  37.  * Oh, of course, you use this stuff entirely at your own risk, I'm not 
  38.  * responsible for any damage this program might cause to you, your computer,
  39.  * your data, your cat, your whateveryoucanthinkof, no warranty whatsoever is
  40.  * granted.
  41.  *
  42.  * I can be reached on internet as: wild@nessie.cs.id.ethz.ch (Markus Wild)
  43.  */
  44.  
  45. #ifndef __GNUC__
  46. #error Sorry, go and figure out how much you have to change, only GCC supported
  47. #endif
  48.  
  49. #include <stdio.h>
  50. #include <exec/types.h>
  51. #include <exec/execbase.h>
  52. #include <inline/exec.h>
  53.  
  54. /*
  55.  * some typedefs for used data structures
  56.  * (mmu-registers, page/table descriptors)
  57.  */
  58.  
  59. /* root pointer registers */
  60. typedef struct {
  61.   unsigned long lu:1,            /* lower/upper.. */
  62.         limit:15,        /* .. limit */
  63.         :14,
  64.         dt:2,            /* descriptor type 0=inv,1=pd,2=std,3=ltd */
  65.         table_addr:28,
  66.         :4;
  67. } rpt_reg;
  68.  
  69.  
  70. /* translation control register */
  71.  
  72. typedef struct {
  73.   unsigned long e:1,            /* crp (poss srp) translation enabled */
  74.           :5,
  75.           sre:1,            /* srp enabled */
  76.           fcl:1,            /* first translation based on function codes */
  77.           ps:4,            /* page-size, see array below for definition */
  78.           is:4,            /* mask that many bits, `32-is' bits are valid */
  79.           tia:4,            /* #bits to be used by this indirection level */
  80.           tib:4,            /* "" */
  81.           tic:4,            /* "" */
  82.           tid:4;            /* "" */
  83. } tc_reg;
  84.  
  85.  
  86. /* transparent translation register */
  87.  
  88. typedef struct {
  89.   unsigned long laddr_base:8,        /* bits 24..31 that have to match */
  90.           laddr_mask:8,        /* mask for base, those bits are don't-care */
  91.           e:1,            /* is this tt enabled ? */
  92.           :4,
  93.           ci:1,            /* cache-inhibit in this area ? */
  94.           rw:1,            /* read/write-only ? ignored when rwm = 1 */
  95.           rwm:1,            /* both read/write ? */
  96.           :1,
  97.           fc_base:3,        /* additional restriction, same rules as laddr.. */
  98.           :1,
  99.           fc_mask:3;        /* mask=%111 -> ignore fc's ;-)) */
  100. } tt_reg;
  101.  
  102.  
  103. /* short table descriptor */
  104.  
  105. typedef struct {
  106.   unsigned long table_addr:28,
  107.         u:1,            /* history-bit, table has been accessed */
  108.         wp:1,            /* protection-bit, table is write-protected */
  109.         dt:2;            /* descriptor type 0=inv,1=pd,2=std,3=ltd */
  110. } short_td;
  111.  
  112.  
  113. /* short page descriptor */
  114.  
  115. typedef struct {
  116.   unsigned long page_addr:24,
  117.           :1,
  118.           ci:1,            /* cache-inhibit on this page */
  119.           :1,
  120.           m:1,            /* modified-bit, page has been modified */
  121.         u:1,            /* history-bit, page has been accessed */
  122.         wp:1,            /* protection-bit, page is write-protected */
  123.         dt:2;             /* descriptor type 0=inv,1=pd,2=sind,3=lind */
  124. } short_pd;
  125.  
  126.  
  127. /* long table descriptor */
  128.  
  129. typedef struct {
  130.   unsigned long lu:1,            /* lower/upper ... */
  131.         limit:15,        /* ... limit */
  132.         :7,
  133.         s:1,            /* supervisor-only tree */
  134.         :4,
  135.         u:1,            /* history-bit, table has been accessed */
  136.         wp:1,            /* protection-bit, page is write-protected */
  137.         dt:2,            /* descriptor type 0=inv,1=pd,2=std,3=ltd */
  138.         table_addr:28,
  139.         :4;
  140. } long_td;
  141.  
  142.  
  143. /* long page descriptor */
  144.  
  145. typedef struct {
  146.   unsigned long lu:1,            /* lower/upper ... */
  147.         limit:15,        /* ... limit */
  148.         :7,
  149.         s:1,            /* supervisor-only page */
  150.         :1,
  151.         ci:1,            /* cache-inhibit on this page */
  152.         :1,
  153.         m:1,            /* modified-bit, page has been modified */
  154.         u:1,            /* history-bit, page has been accessed */
  155.         wp:1,            /* protection-bit, page is write-protected */
  156.         dt:2,             /* descriptor type 0=inv,1=pd,2=sind,3=lind */
  157.         page_addr:24,
  158.         :8;
  159. } long_pd;
  160.  
  161.  
  162. /***************************************************************************/
  163.  
  164. char *dt_name[] = { /* 0 */ "INVALID",
  165.             /* 1 */ "PAGE DESCRIPTOR",
  166.             /* 2 */ "SHORT FORMAT TABLE DESCRIPTOR",
  167.             /* 3 */ "LONG  FORMAT TABLE DESCRIPTOR", };
  168.  
  169. char *bool_state[] = { "off", "on", };
  170.  
  171. char *limit_mode[] = { "upper", "lower", };
  172.  
  173. char *page_sizes[] = { "res", "res", "res", "res", "res", "res", "res", "res", 
  174.                "256", "512", "1k", "2k", "4k", "8k", "16k", "32k", };
  175.  
  176. /***************************************************************************/
  177.  
  178. /* copy of the current PMMU registers */
  179.  
  180. rpt_reg crp, srp;
  181. tt_reg  tt0, tt1;
  182. tc_reg  tc;
  183.  
  184. /***************************************************************************/
  185.  
  186. /*
  187.  * make private copies of  the currently used MMU-registers
  188.  */
  189.  
  190. static void inline
  191. load_regs ()
  192. {
  193.   asm volatile ("
  194.     | looks somewhat horrible, but it's a royal pain in the a* to fiddle
  195.     | with the framepointer without telling gcc, couldn't Supervisor()
  196.     | use another register than a5? This is really a mean function ;-))
  197.     exg    a5,a4
  198.     lea    L12345,a5
  199.     exg    a6,a3
  200.     movel    4,a6
  201.     jsr    a6@(-30)    | _LVOSupervisor, don't like this HUGE amiga.lib..
  202.     exg    a6,a3
  203.     exg    a5,a4
  204.     bra    L12456
  205. L12345:
  206.     pmove crp,_crp
  207.     pmove srp,_srp
  208.     btst  #2,(4)@(0x129)    | `btst #AFB_68030,AttnFlags+1(SysBase)'
  209.     beq   is_68851
  210.     .word 0xf039,0x0a00    | pmove tt0,_tt0 (gas only knows about 68851 ops..)
  211.     .long _tt0
  212.     .word 0xf039,0x0e00    | pmove tt1,_tt1
  213.     .long _tt1
  214.     bra   read_tc
  215. is_68851:
  216.     clrl  _tt0        | by clearing it we also disable the
  217.     clrl  _tt1        | enabled-bit, so the register is ignored later
  218. read_tc: 
  219.     pmove tc,_tc
  220.     rte
  221. L12456:
  222.     " : : : "a0", "a1", "a3", "a4", "d0", "d1"); /* asm() clobbered these regs */
  223. }
  224.  
  225. /***************************************************************************/
  226.  
  227. static void inline
  228. print_rptr (rpt_reg *rp, char *name)
  229. {
  230.   printf ("%s: ", name);
  231.   printf ("%s limit= $%04x, desc= %s, table_addr= $%08x\n",
  232.       limit_mode[rp->lu], rp->limit, dt_name[rp->dt], rp->table_addr << 4);
  233. }
  234.  
  235. static void inline
  236. print_tt (tt_reg *tt, char *name)
  237. {
  238.   printf ("%s: ", name);
  239.   printf ("addr_base= $%x, addr_mask= $%x -> range $%08x - $%08x\n"
  240.       "     ena= %s, cache-inh= %s, allow %s, "
  241.       "fc_base= $%x, fc_mask= $%x\n",
  242.       tt->laddr_base, tt->laddr_mask,
  243.       tt->laddr_base << 24, 
  244.       (tt->laddr_base<<24) + (tt->laddr_mask<<24) + ((1<<24)-1),
  245.       bool_state[tt->e], bool_state[tt->ci], 
  246.       tt->rwm ? "read and write" : (tt->rw ? "only read" : "only write"),
  247.       tt->fc_base, tt->fc_mask);
  248. }
  249.  
  250. static void inline
  251. print_tc (tc_reg *tc)
  252. {
  253.   printf ("tc:  ena= %s, sre= %s, fcl= %s, page size= %s, valid bits= %d,\n"
  254.       "     Level-A= %d, Level-B= %d, Level-C= %d, Level-D= %d bits\n",
  255.       bool_state[tc->e], bool_state[tc->sre], bool_state[tc->fcl],
  256.       page_sizes[tc->ps], 32 - tc->is, tc->tia, tc->tib, tc->tic, tc->tid);
  257. }
  258.  
  259.  
  260. /***************************************************************************/
  261.  
  262. /*
  263.  * Calculate the range a table-entry applies to. Does no checks at all ;-) 
  264.  */
  265.  
  266. static void inline
  267. calc_range (void *base, int index, int level, void **lower, void **upper)
  268. {
  269.   unsigned char *low, *up;
  270.   
  271.   low = (unsigned char *) base;
  272.   up  = 0;
  273.   switch (level)
  274.     {
  275.     case 1:
  276.       low += index * (1 << (32 - tc.tia));
  277.       up   = low   + (1 << (32 - tc.tia)) - 1;
  278.       break;
  279.  
  280.     case 2:
  281.       low += index * (1 << (32 - tc.tia - tc.tib));
  282.       up   = low   + (1 << (32 - tc.tia - tc.tib)) - 1;
  283.       break;
  284.  
  285.     case 3:
  286.       low += index * (1 << (32 - tc.tia - tc.tib - tc.tic));
  287.       up   = low   + (1 << (32 - tc.tia - tc.tib - tc.tic)) - 1;
  288.       break;
  289.  
  290.     case 4:
  291.       low += index * (1 << (32 - tc.tia - tc.tib - tc.tic - tc.tid));
  292.       up   = low   + (1 << (32 - tc.tia - tc.tib - tc.tic - tc.tid)) - 1;
  293.       break;
  294.     }
  295.  
  296.   *lower = (void *)low;
  297.   *upper = (void *)up;
  298. }
  299.  
  300.  
  301. /***************************************************************************/
  302.  
  303. /*
  304.  * Recursively dump a page table, stop after dumping a page descriptor
  305.  */
  306.  
  307. static void
  308. dump_descr (int from, int to,    /* index limit from the parent table */
  309.         int indent,         /* how many spaces to indent the line */
  310.         int is_long,     /* expect 4byte or 8byte entries */
  311.         void *table,     /* any of the table/page descriptors */
  312.         void *base,         /* the base address this table manages */
  313.         int level)         /* 1-4, for 'tia' till 'tid' */
  314. {
  315.   /* only this index range is defined... */
  316.   to &= (1<<( level == 1 ? tc.tia :
  317.           ( level == 2 ? tc.tib :
  318.         ( level == 3 ? tc.tic : tc.tid )))) - 1;
  319.  
  320.   if (is_long) /* LONG FORMAT */
  321.     {
  322.       long_td *td;
  323.       
  324.       for (td = (long_td *)table + from; td <= (long_td *)table + to; td++)
  325.     {
  326.       void *lower, *upper;
  327.       
  328.       calc_range (base, td - (long_td *)table, level, &lower, &upper);
  329.  
  330.       printf ("%*d %s", indent, td-(long_td*)table, dt_name[td->dt]);
  331.  
  332.       if (td->dt == 0) /* INVALID */
  333.         printf (" $%08x - $%08x (custom: $%08x%08x)\n",
  334.             lower, upper,
  335.             *(long *)td & ~3, *(((long*)td)+1));
  336.       else if (td->dt == 1) /* PAGEDESC */
  337.         {
  338.           long_pd *pd = (long_pd *) td;
  339.           
  340.           printf (" %s limit: $%04x\n", limit_mode[pd->lu], pd->limit);
  341.           printf ("%*s superv: %s, cache-inh: %s, mod: %s, hist: %s, wprot: %s\n",
  342.               indent+1+strlen(dt_name[pd->dt])+1, "|",
  343.               bool_state[pd->s], bool_state[pd->ci], bool_state[pd->m],
  344.               bool_state[pd->u], bool_state[pd->wp]);
  345.           printf ("%*s range: ", indent+1+strlen(dt_name[pd->dt])+1, "|");
  346.           printf ("$%08x - $%08x -> @$%08x\n", lower, upper, pd->page_addr << 8);
  347.         }
  348.       else if (td->dt == 2 || td->dt == 3)  /* TABLEDESC */
  349.         {
  350.           printf (" %s limit: $%04x\n", limit_mode[td->lu], td->limit);
  351.           printf ("%*s superv: %s, hist: %s, wprot: %s\n",
  352.               indent+1+strlen(dt_name[td->dt])+1, "|",
  353.               bool_state[td->s],
  354.               bool_state[td->u], bool_state[td->wp]);
  355.           printf ("%*s range: ", indent+1+strlen(dt_name[td->dt])+1, "|");
  356.           printf ("$%08x - $%08x -> @$%08x\n", lower, upper, td->table_addr << 4);
  357.           dump_descr (td->lu ? td->limit : 0,
  358.                     td->lu ? 0x7fff : td->limit,
  359.                     indent + 4,
  360.                     td->dt == 3,
  361.                     (void *)(td->table_addr << 4),
  362.                     lower,
  363.                     level+1);
  364.         }
  365.     }
  366.     }
  367.   else /* SHORT FORMAT */
  368.     {
  369.       short_td *td;
  370.       
  371.       for (td = (short_td *)table + from; td <= (short_td *)table + to; td++)
  372.     {
  373.       void *lower, *upper;
  374.       
  375.       calc_range (base, td - (short_td *)table, level, &lower, &upper);
  376.  
  377.       printf ("%*d %s", indent, td-(short_td*)table, dt_name[td->dt]);
  378.  
  379.       if (td->dt == 0) /* INVALID */
  380.         printf (" $%08x - $%08x (custom: $%08x)\n",
  381.             lower, upper,
  382.             *(long *)td & ~3);
  383.       else if (td->dt == 1) /* PAGEDESC */
  384.         {
  385.           short_pd *pd = (short_pd *) td;
  386.           
  387.           printf ("/ cache-inh: %s, mod: %s, hist: %s, wprot: %s\n",
  388.               bool_state[pd->ci], bool_state[pd->m],
  389.               bool_state[pd->u], bool_state[pd->wp]);
  390.           printf ("%*s range: ", indent+1+strlen(dt_name[pd->dt])+1, "|");
  391.           printf ("$%08x - $%08x -> @$%08x\n", lower, upper, pd->page_addr << 8);
  392.         }
  393.       else if (td->dt == 2 || td->dt == 3) /* TABLEDESC */
  394.         {
  395.           printf ("/ hist: %s, wprot: %s\n", bool_state[td->u], bool_state[td->wp]);
  396.           printf ("%*s range: ", indent+1+strlen(dt_name[td->dt])+1, "|");
  397.           printf ("$%08x - $%08x -> @$%08x\n", lower, upper, td->table_addr << 4);
  398.           dump_descr (0, 0x7fff,
  399.                     indent + 4,
  400.                     td->dt == 3,
  401.                     (void *)(td->table_addr << 4),
  402.                     lower,
  403.                     level+1);
  404.         }
  405.     }
  406.     }
  407. }
  408.  
  409.  
  410. int
  411. main ()
  412. {
  413.   int i;
  414.   char ch;
  415.  
  416.   if (!(((*(struct ExecBase **)4))->AttnFlags & AFF_68020))
  417.     {
  418.       printf ("Feeling adventurous eh? If you really want use this nice tool just\n");
  419.       printf ("to generate a guru, go ahead, you might consider to abort as well...\n");
  420.       printf ("\nVisit the guru now ? [n]"); fflush (stdout);
  421.       ch = getchar ();
  422.       /* so even Germans can have their gurus ;-)) */
  423.       if (ch == 'y' || ch == 'Y' || ch == 'j' || ch == 'J')
  424.     printf ("\nHere we go...\n");
  425.       else
  426.     return 20;
  427.     }
  428.   
  429.   load_regs ();
  430.  
  431.   print_tc (&tc);
  432.  
  433.   /* The following tests check to only output enabled data */
  434.   if (tc.e)        print_rptr (&crp, "crp");
  435.   if (tc.e && tc.sre)    print_rptr (&srp, "srp");
  436.   if (tt0.e)        print_tt   (&tt0, "tt0");
  437.   if (tt1.e)        print_tt   (&tt1, "tt1");
  438.   printf ("\n");
  439.   if (tc.e)
  440.     {
  441.       printf (">> CRP <<\n");
  442.       dump_descr (crp.lu ? crp.limit : 0,
  443.               crp.lu ? 0x7fff : crp.limit,
  444.               4,
  445.               crp.dt == 3,
  446.               (void *)(crp.table_addr << 4),
  447.               0,
  448.               1);
  449.     }
  450.   if (tc.e && tc.sre)
  451.     {
  452.       printf ("\n>> SRP <<\n");
  453.       dump_descr (srp.lu ? srp.limit : 0,
  454.               srp.lu ? 0x7fff : srp.limit,
  455.               4,
  456.               srp.dt == 3,
  457.               (void *)(srp.table_addr << 4),
  458.               0,
  459.               1);
  460.     }
  461.  
  462.   return 0;
  463. }
  464.