home *** CD-ROM | disk | FTP | other *** search
- ;/* this is how to compile this program in a gcc(2.0)-environment
-
- ; this trick enables us to generate 68020 code, but the very start of the
- ; program runs on a 68000 as well. -mc68000 inhibits gas' jsr->bsr
- ; transformation at the cost of generating lots more reloc32 than necessary
- gcc2 -O2 -S -mc68020 showmmu.c
- gcc2 -mc68000 showmmu.s -o showmmu
- quit
- */
-
- /*
- * Dump the current MMU table and show the various MMU status flags (except
- * the status-register itself, which isn't really useful if not doing explicit
- * address translation).
- * If you want to learn about how the MMU works, I strongly recommend you
- * read either the 68851 or the 68030 user manual, they explain `everything'
- * you want to know, and more ;-)
- * This program has been written for a 68030 MMU, it doesn't support 68851-only
- * features, since I can't test them, and I don't need them ;-)
- * This program is my first attempt at understanding how `my' MMU works, and
- * I guess I know enough now to try to write my own tables;-)
- *
- * V1.0 91-10-7 M. Wild first hack (it's a one-session hack I admit ;-))
- * Bugs: o No indirect page-descriptors. If they're used,
- * they're translated as table-descriptors, with quite
- * possibly a deadly (hi guru;-)) result
- * o No checks for too deeply nested tables (same applies
- * as above). This is not too bad, since only active
- * page tables are dumped, they already have proven to
- * be somewhat sensible...
- * o No support for function codes. Same scenario to be
- * expected as in the above cases...
- *
- * This is free software. This means that I don't care what you do with it
- * as long as you don't claim you wrote it. If you enhance it, please
- * send me your diffs!
- * Oh, of course, you use this stuff entirely at your own risk, I'm not
- * responsible for any damage this program might cause to you, your computer,
- * your data, your cat, your whateveryoucanthinkof, no warranty whatsoever is
- * granted.
- *
- * I can be reached on internet as: wild@nessie.cs.id.ethz.ch (Markus Wild)
- */
-
- #ifndef __GNUC__
- #error Sorry, go and figure out how much you have to change, only GCC supported
- #endif
-
- #include <stdio.h>
- #include <exec/types.h>
- #include <exec/execbase.h>
- #include <inline/exec.h>
-
- /*
- * some typedefs for used data structures
- * (mmu-registers, page/table descriptors)
- */
-
- /* root pointer registers */
- typedef struct {
- unsigned long lu:1, /* lower/upper.. */
- limit:15, /* .. limit */
- :14,
- dt:2, /* descriptor type 0=inv,1=pd,2=std,3=ltd */
- table_addr:28,
- :4;
- } rpt_reg;
-
-
- /* translation control register */
-
- typedef struct {
- unsigned long e:1, /* crp (poss srp) translation enabled */
- :5,
- sre:1, /* srp enabled */
- fcl:1, /* first translation based on function codes */
- ps:4, /* page-size, see array below for definition */
- is:4, /* mask that many bits, `32-is' bits are valid */
- tia:4, /* #bits to be used by this indirection level */
- tib:4, /* "" */
- tic:4, /* "" */
- tid:4; /* "" */
- } tc_reg;
-
-
- /* transparent translation register */
-
- typedef struct {
- unsigned long laddr_base:8, /* bits 24..31 that have to match */
- laddr_mask:8, /* mask for base, those bits are don't-care */
- e:1, /* is this tt enabled ? */
- :4,
- ci:1, /* cache-inhibit in this area ? */
- rw:1, /* read/write-only ? ignored when rwm = 1 */
- rwm:1, /* both read/write ? */
- :1,
- fc_base:3, /* additional restriction, same rules as laddr.. */
- :1,
- fc_mask:3; /* mask=%111 -> ignore fc's ;-)) */
- } tt_reg;
-
-
- /* short table descriptor */
-
- typedef struct {
- unsigned long table_addr:28,
- u:1, /* history-bit, table has been accessed */
- wp:1, /* protection-bit, table is write-protected */
- dt:2; /* descriptor type 0=inv,1=pd,2=std,3=ltd */
- } short_td;
-
-
- /* short page descriptor */
-
- typedef struct {
- unsigned long page_addr:24,
- :1,
- ci:1, /* cache-inhibit on this page */
- :1,
- m:1, /* modified-bit, page has been modified */
- u:1, /* history-bit, page has been accessed */
- wp:1, /* protection-bit, page is write-protected */
- dt:2; /* descriptor type 0=inv,1=pd,2=sind,3=lind */
- } short_pd;
-
-
- /* long table descriptor */
-
- typedef struct {
- unsigned long lu:1, /* lower/upper ... */
- limit:15, /* ... limit */
- :7,
- s:1, /* supervisor-only tree */
- :4,
- u:1, /* history-bit, table has been accessed */
- wp:1, /* protection-bit, page is write-protected */
- dt:2, /* descriptor type 0=inv,1=pd,2=std,3=ltd */
- table_addr:28,
- :4;
- } long_td;
-
-
- /* long page descriptor */
-
- typedef struct {
- unsigned long lu:1, /* lower/upper ... */
- limit:15, /* ... limit */
- :7,
- s:1, /* supervisor-only page */
- :1,
- ci:1, /* cache-inhibit on this page */
- :1,
- m:1, /* modified-bit, page has been modified */
- u:1, /* history-bit, page has been accessed */
- wp:1, /* protection-bit, page is write-protected */
- dt:2, /* descriptor type 0=inv,1=pd,2=sind,3=lind */
- page_addr:24,
- :8;
- } long_pd;
-
-
- /***************************************************************************/
-
- char *dt_name[] = { /* 0 */ "INVALID",
- /* 1 */ "PAGE DESCRIPTOR",
- /* 2 */ "SHORT FORMAT TABLE DESCRIPTOR",
- /* 3 */ "LONG FORMAT TABLE DESCRIPTOR", };
-
- char *bool_state[] = { "off", "on", };
-
- char *limit_mode[] = { "upper", "lower", };
-
- char *page_sizes[] = { "res", "res", "res", "res", "res", "res", "res", "res",
- "256", "512", "1k", "2k", "4k", "8k", "16k", "32k", };
-
- /***************************************************************************/
-
- /* copy of the current PMMU registers */
-
- rpt_reg crp, srp;
- tt_reg tt0, tt1;
- tc_reg tc;
-
- /***************************************************************************/
-
- /*
- * make private copies of the currently used MMU-registers
- */
-
- static void inline
- load_regs ()
- {
- asm volatile ("
- | looks somewhat horrible, but it's a royal pain in the a* to fiddle
- | with the framepointer without telling gcc, couldn't Supervisor()
- | use another register than a5? This is really a mean function ;-))
- exg a5,a4
- lea L12345,a5
- exg a6,a3
- movel 4,a6
- jsr a6@(-30) | _LVOSupervisor, don't like this HUGE amiga.lib..
- exg a6,a3
- exg a5,a4
- bra L12456
- L12345:
- pmove crp,_crp
- pmove srp,_srp
- btst #2,(4)@(0x129) | `btst #AFB_68030,AttnFlags+1(SysBase)'
- beq is_68851
- .word 0xf039,0x0a00 | pmove tt0,_tt0 (gas only knows about 68851 ops..)
- .long _tt0
- .word 0xf039,0x0e00 | pmove tt1,_tt1
- .long _tt1
- bra read_tc
- is_68851:
- clrl _tt0 | by clearing it we also disable the
- clrl _tt1 | enabled-bit, so the register is ignored later
- read_tc:
- pmove tc,_tc
- rte
- L12456:
- " : : : "a0", "a1", "a3", "a4", "d0", "d1"); /* asm() clobbered these regs */
- }
-
- /***************************************************************************/
-
- static void inline
- print_rptr (rpt_reg *rp, char *name)
- {
- printf ("%s: ", name);
- printf ("%s limit= $%04x, desc= %s, table_addr= $%08x\n",
- limit_mode[rp->lu], rp->limit, dt_name[rp->dt], rp->table_addr << 4);
- }
-
- static void inline
- print_tt (tt_reg *tt, char *name)
- {
- printf ("%s: ", name);
- printf ("addr_base= $%x, addr_mask= $%x -> range $%08x - $%08x\n"
- " ena= %s, cache-inh= %s, allow %s, "
- "fc_base= $%x, fc_mask= $%x\n",
- tt->laddr_base, tt->laddr_mask,
- tt->laddr_base << 24,
- (tt->laddr_base<<24) + (tt->laddr_mask<<24) + ((1<<24)-1),
- bool_state[tt->e], bool_state[tt->ci],
- tt->rwm ? "read and write" : (tt->rw ? "only read" : "only write"),
- tt->fc_base, tt->fc_mask);
- }
-
- static void inline
- print_tc (tc_reg *tc)
- {
- printf ("tc: ena= %s, sre= %s, fcl= %s, page size= %s, valid bits= %d,\n"
- " Level-A= %d, Level-B= %d, Level-C= %d, Level-D= %d bits\n",
- bool_state[tc->e], bool_state[tc->sre], bool_state[tc->fcl],
- page_sizes[tc->ps], 32 - tc->is, tc->tia, tc->tib, tc->tic, tc->tid);
- }
-
-
- /***************************************************************************/
-
- /*
- * Calculate the range a table-entry applies to. Does no checks at all ;-)
- */
-
- static void inline
- calc_range (void *base, int index, int level, void **lower, void **upper)
- {
- unsigned char *low, *up;
-
- low = (unsigned char *) base;
- up = 0;
- switch (level)
- {
- case 1:
- low += index * (1 << (32 - tc.tia));
- up = low + (1 << (32 - tc.tia)) - 1;
- break;
-
- case 2:
- low += index * (1 << (32 - tc.tia - tc.tib));
- up = low + (1 << (32 - tc.tia - tc.tib)) - 1;
- break;
-
- case 3:
- low += index * (1 << (32 - tc.tia - tc.tib - tc.tic));
- up = low + (1 << (32 - tc.tia - tc.tib - tc.tic)) - 1;
- break;
-
- case 4:
- low += index * (1 << (32 - tc.tia - tc.tib - tc.tic - tc.tid));
- up = low + (1 << (32 - tc.tia - tc.tib - tc.tic - tc.tid)) - 1;
- break;
- }
-
- *lower = (void *)low;
- *upper = (void *)up;
- }
-
-
- /***************************************************************************/
-
- /*
- * Recursively dump a page table, stop after dumping a page descriptor
- */
-
- static void
- dump_descr (int from, int to, /* index limit from the parent table */
- int indent, /* how many spaces to indent the line */
- int is_long, /* expect 4byte or 8byte entries */
- void *table, /* any of the table/page descriptors */
- void *base, /* the base address this table manages */
- int level) /* 1-4, for 'tia' till 'tid' */
- {
- /* only this index range is defined... */
- to &= (1<<( level == 1 ? tc.tia :
- ( level == 2 ? tc.tib :
- ( level == 3 ? tc.tic : tc.tid )))) - 1;
-
- if (is_long) /* LONG FORMAT */
- {
- long_td *td;
-
- for (td = (long_td *)table + from; td <= (long_td *)table + to; td++)
- {
- void *lower, *upper;
-
- calc_range (base, td - (long_td *)table, level, &lower, &upper);
-
- printf ("%*d %s", indent, td-(long_td*)table, dt_name[td->dt]);
-
- if (td->dt == 0) /* INVALID */
- printf (" $%08x - $%08x (custom: $%08x%08x)\n",
- lower, upper,
- *(long *)td & ~3, *(((long*)td)+1));
- else if (td->dt == 1) /* PAGEDESC */
- {
- long_pd *pd = (long_pd *) td;
-
- printf (" %s limit: $%04x\n", limit_mode[pd->lu], pd->limit);
- printf ("%*s superv: %s, cache-inh: %s, mod: %s, hist: %s, wprot: %s\n",
- indent+1+strlen(dt_name[pd->dt])+1, "|",
- bool_state[pd->s], bool_state[pd->ci], bool_state[pd->m],
- bool_state[pd->u], bool_state[pd->wp]);
- printf ("%*s range: ", indent+1+strlen(dt_name[pd->dt])+1, "|");
- printf ("$%08x - $%08x -> @$%08x\n", lower, upper, pd->page_addr << 8);
- }
- else if (td->dt == 2 || td->dt == 3) /* TABLEDESC */
- {
- printf (" %s limit: $%04x\n", limit_mode[td->lu], td->limit);
- printf ("%*s superv: %s, hist: %s, wprot: %s\n",
- indent+1+strlen(dt_name[td->dt])+1, "|",
- bool_state[td->s],
- bool_state[td->u], bool_state[td->wp]);
- printf ("%*s range: ", indent+1+strlen(dt_name[td->dt])+1, "|");
- printf ("$%08x - $%08x -> @$%08x\n", lower, upper, td->table_addr << 4);
- dump_descr (td->lu ? td->limit : 0,
- td->lu ? 0x7fff : td->limit,
- indent + 4,
- td->dt == 3,
- (void *)(td->table_addr << 4),
- lower,
- level+1);
- }
- }
- }
- else /* SHORT FORMAT */
- {
- short_td *td;
-
- for (td = (short_td *)table + from; td <= (short_td *)table + to; td++)
- {
- void *lower, *upper;
-
- calc_range (base, td - (short_td *)table, level, &lower, &upper);
-
- printf ("%*d %s", indent, td-(short_td*)table, dt_name[td->dt]);
-
- if (td->dt == 0) /* INVALID */
- printf (" $%08x - $%08x (custom: $%08x)\n",
- lower, upper,
- *(long *)td & ~3);
- else if (td->dt == 1) /* PAGEDESC */
- {
- short_pd *pd = (short_pd *) td;
-
- printf ("/ cache-inh: %s, mod: %s, hist: %s, wprot: %s\n",
- bool_state[pd->ci], bool_state[pd->m],
- bool_state[pd->u], bool_state[pd->wp]);
- printf ("%*s range: ", indent+1+strlen(dt_name[pd->dt])+1, "|");
- printf ("$%08x - $%08x -> @$%08x\n", lower, upper, pd->page_addr << 8);
- }
- else if (td->dt == 2 || td->dt == 3) /* TABLEDESC */
- {
- printf ("/ hist: %s, wprot: %s\n", bool_state[td->u], bool_state[td->wp]);
- printf ("%*s range: ", indent+1+strlen(dt_name[td->dt])+1, "|");
- printf ("$%08x - $%08x -> @$%08x\n", lower, upper, td->table_addr << 4);
- dump_descr (0, 0x7fff,
- indent + 4,
- td->dt == 3,
- (void *)(td->table_addr << 4),
- lower,
- level+1);
- }
- }
- }
- }
-
-
- int
- main ()
- {
- int i;
- char ch;
-
- if (!(((*(struct ExecBase **)4))->AttnFlags & AFF_68020))
- {
- printf ("Feeling adventurous eh? If you really want use this nice tool just\n");
- printf ("to generate a guru, go ahead, you might consider to abort as well...\n");
- printf ("\nVisit the guru now ? [n]"); fflush (stdout);
- ch = getchar ();
- /* so even Germans can have their gurus ;-)) */
- if (ch == 'y' || ch == 'Y' || ch == 'j' || ch == 'J')
- printf ("\nHere we go...\n");
- else
- return 20;
- }
-
- load_regs ();
-
- print_tc (&tc);
-
- /* The following tests check to only output enabled data */
- if (tc.e) print_rptr (&crp, "crp");
- if (tc.e && tc.sre) print_rptr (&srp, "srp");
- if (tt0.e) print_tt (&tt0, "tt0");
- if (tt1.e) print_tt (&tt1, "tt1");
- printf ("\n");
- if (tc.e)
- {
- printf (">> CRP <<\n");
- dump_descr (crp.lu ? crp.limit : 0,
- crp.lu ? 0x7fff : crp.limit,
- 4,
- crp.dt == 3,
- (void *)(crp.table_addr << 4),
- 0,
- 1);
- }
- if (tc.e && tc.sre)
- {
- printf ("\n>> SRP <<\n");
- dump_descr (srp.lu ? srp.limit : 0,
- srp.lu ? 0x7fff : srp.limit,
- 4,
- srp.dt == 3,
- (void *)(srp.table_addr << 4),
- 0,
- 1);
- }
-
- return 0;
- }
-