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 >
Wrap
C/C++ Source or Header
|
1991-10-08
|
14KB
|
464 lines
;/* 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;
}