xref: /csrg-svn/old/adb/adb.hp300/access.c (revision 62649)
162641Shibler #ifndef lint
262641Shibler static	char sccsid[] = "@(#)access.c	4.8 10/13/84";
362641Shibler #endif
462641Shibler /*
562641Shibler  * Adb: access data in file/process address space.
662641Shibler  *
762641Shibler  * The routines in this file access referenced data using
862641Shibler  * the maps to access files, ptrace to access subprocesses,
962641Shibler  * or the system page tables when debugging the kernel,
1062641Shibler  * to translate virtual to physical addresses.
1162641Shibler  */
1262641Shibler 
1362641Shibler #include "defs.h"
1462641Shibler 
1562641Shibler 
1662641Shibler MAP		txtmap;
1762641Shibler MAP		datmap;
1862641Shibler INT		wtflag;
1962641Shibler STRING		errflg;
2062641Shibler int		errno;
2162641Shibler 
2262641Shibler INT		pid;
2362641Shibler 
2462641Shibler /*
2562641Shibler  * Primitives: put a value in a space, get a value from a space
2662641Shibler  * and get a word or byte not returning if an error occurred.
2762641Shibler  */
put(addr,space,value)2862641Shibler put(addr, space, value)
2962641Shibler     off_t addr; { (void) access(WT, addr, space, value); }
3062641Shibler 
3162641Shibler #if vax || pdp11
3262641Shibler u_int
get(addr,space)3362641Shibler get(addr, space)
3462641Shibler     off_t addr; { return (access(RD, addr, space, 0)); }
3562641Shibler 
3662641Shibler u_int
lchkget(addr,space)3762641Shibler lchkget(addr, space)
3862641Shibler     off_t addr; { u_int w = get(addr, space); chkerr(); return(w); }
3962641Shibler #endif
4062641Shibler 
4162641Shibler #ifdef mc68000
4262641Shibler /*
4362641Shibler  * 68000 Unices don't like odd addresses.
4462641Shibler  */
4562641Shibler u_int
get(addr,space)4662641Shibler get(addr, space)
4762641Shibler     off_t addr;
4862641Shibler {
4962641Shibler     u_int data;
5062641Shibler 
5162641Shibler     if (addr & 1) {
5262641Shibler 	data = access(RD, addr - 1, space, 0);
5362641Shibler 	return ((data >> 8) & 0xffff);
5462641Shibler     }
5562641Shibler     data = access(RD, addr, space, 0);
5662641Shibler     return ((data >> 16) & 0xffff);
5762641Shibler }
5862641Shibler 
5962641Shibler u_int
lget(addr,space)6062641Shibler lget(addr, space)
6162641Shibler     off_t addr;
6262641Shibler {
6362641Shibler     if (addr & 1) {
6462641Shibler 	u_int data = get(addr, space);
6562641Shibler 	return (get(addr + 2, space) | (data << 16));
6662641Shibler     }
6762641Shibler     return (access(RD, addr, space, 0));
6862641Shibler }
6962641Shibler 
7062641Shibler u_int
lchkget(addr,space)7162641Shibler lchkget(addr, space)
7262641Shibler     off_t addr; { u_int w = lget(addr, space); chkerr(); return(w); }
7362641Shibler #endif
7462641Shibler 
7562641Shibler #if !pdp11 && !vax && !mc68000
7662641Shibler help!
7762641Shibler #endif
7862641Shibler 
7962641Shibler u_int
chkget(addr,space)8062641Shibler chkget(addr, space)
8162641Shibler     off_t addr; { u_int w = get(addr, space); chkerr(); return(w); }
8262641Shibler 
8362641Shibler u_int
bchkget(addr,space)8462641Shibler bchkget(addr, space)
8562641Shibler     off_t addr; { return(lobyte(chkget(addr, space))); }
8662641Shibler 
8762641Shibler /*
8862641Shibler  * Read/write according to mode at address addr in i/d space.
8962641Shibler  * Value is quantity to be written, if write.
9062641Shibler  *
9162641Shibler  * This routine decides whether to get the data from the subprocess
9262641Shibler  * address space with ptrace, or to get it from the files being
9362641Shibler  * debugged.
9462641Shibler  *
9562641Shibler  * When the kernel is being debugged with the -k flag we interpret
9662641Shibler  * the system page tables for data space, mapping p0 and p1 addresses
9762641Shibler  * relative to the ``current'' process (as specified by its p_addr in
9862641Shibler  * <p) and mapping system space addresses through the system page tables.
9962641Shibler  */
access(mode,addr,space,value)10062641Shibler access(mode, addr, space, value)
10162641Shibler 	int mode, space, value;
10262641Shibler 	off_t addr;
10362641Shibler {
10462641Shibler 	int rd = mode == RD;
10562641Shibler 	int file, w;
10662641Shibler 
10762641Shibler 	if (space == NSP)
10862641Shibler 		return(0);
10962641Shibler 	if (pid) {
11062641Shibler 		int pmode = (space&DSP ?
11162641Shibler 		    (rd ? PT_READ_D : PT_WRITE_D) :
11262641Shibler 		    (rd ? PT_READ_I : PT_WRITE_I));
11362641Shibler 
11462641Shibler 		w = ptrace(pmode, pid, addr, value);
11562641Shibler 		if (errno)
11662641Shibler 			rwerr(space);
11762641Shibler 		return (w);
11862641Shibler 	}
11962641Shibler 	w = 0;
12062641Shibler 	if (mode==WT && wtflag==0)
12162641Shibler 		error("not in write mode");
12262641Shibler 	if (!chkmap(&addr, space))
12362641Shibler 		return (0);
12462641Shibler 	file = mapptr(space)->ufd;
12562641Shibler 	if (kernel && space == DSP) {
12662641Shibler 		addr = vtophys(addr);
12762641Shibler 		if (addr == -1)
12862641Shibler 			return (0);
12962641Shibler 	}
13062641Shibler 	if (physrw(file, addr, rd ? &w : &value, rd) < 0)
13162641Shibler 		rwerr(space);
13262641Shibler 	return (w);
13362641Shibler }
13462641Shibler 
13562641Shibler #ifdef vax
13662641Shibler /*
13762641Shibler  * When looking at kernel data space through /dev/mem or
13862641Shibler  * with a core file, do virtual memory mapping.
13962641Shibler  */
vtophys(addr)14062641Shibler vtophys(addr)
14162641Shibler 	off_t addr;
14262641Shibler {
14362641Shibler 	int oldaddr = addr;
14462641Shibler 	int v;
14562641Shibler 	struct pte pte;
14662641Shibler 
14762641Shibler 	addr &= ~0xc0000000;
14862641Shibler 	v = btop(addr);
14962641Shibler 	switch (oldaddr&0xc0000000) {
15062641Shibler 
15162641Shibler 	case 0xc0000000:
15262641Shibler 	case 0x80000000:
15362641Shibler 		/*
15462641Shibler 		 * In system space get system pte.  If
15562641Shibler 		 * valid or reclaimable then physical address
15662641Shibler 		 * is combination of its page number and the page
15762641Shibler 		 * offset of the original address.
15862641Shibler 		 */
15962641Shibler 		if (v >= slr)
16062641Shibler 			goto oor;
16162641Shibler 		addr = ((long)(sbr+v)) &~ 0x80000000;
16262641Shibler 		goto simple;
16362641Shibler 
16462641Shibler 	case 0x40000000:
16562641Shibler 		/*
16662641Shibler 		 * In p1 space must not be in shadow region.
16762641Shibler 		 */
16862641Shibler 		if (v < pcb.pcb_p1lr)
16962641Shibler 			goto oor;
17062641Shibler 		addr = pcb.pcb_p1br+v;
17162641Shibler 		break;
17262641Shibler 
17362641Shibler 	case 0x00000000:
17462641Shibler 		/*
17562641Shibler 		 * In p0 space must not be off end of region.
17662641Shibler 		 */
17762641Shibler 		if (v >= pcb.pcb_p0lr)
17862641Shibler 			goto oor;
17962641Shibler 		addr = pcb.pcb_p0br+v;
18062641Shibler 		break;
18162641Shibler 	oor:
18262641Shibler 		errflg = "address out of segment";
18362641Shibler 		return (-1);
18462641Shibler 	}
18562641Shibler 	/*
18662641Shibler 	 * For p0/p1 address, user-level page table should
18762641Shibler 	 * be in kernel vm.  Do second-level indirect by recursing.
18862641Shibler 	 */
18962641Shibler 	if ((addr & 0x80000000) == 0) {
19062641Shibler 		errflg = "bad p0br or p1br in pcb";
19162641Shibler 		return (-1);
19262641Shibler 	}
19362641Shibler 	addr = vtophys(addr);
19462641Shibler simple:
19562641Shibler 	/*
19662641Shibler 	 * Addr is now address of the pte of the page we
19762641Shibler 	 * are interested in; get the pte and paste up the
19862641Shibler 	 * physical address.
19962641Shibler 	 */
20062641Shibler 	if (physrw(fcor, addr, (int *)&pte, 1) < 0) {
20162641Shibler 		errflg = "page table botch";
20262641Shibler 		return (-1);
20362641Shibler 	}
20462641Shibler 	/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
20562641Shibler 	if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) {
20662641Shibler 		errflg = "page not valid/reclaimable";
20762641Shibler 		return (-1);
20862641Shibler 	}
20962641Shibler 	return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
21062641Shibler }
21162641Shibler #endif
21262641Shibler 
21362641Shibler #ifdef hp300
21462641Shibler 
21562641Shibler #ifdef NEWVM
21662641Shibler #ifndef btop
21762641Shibler #define btop	hp300_btop
21862641Shibler #endif
21962641Shibler #ifndef ptob
22062641Shibler #define ptob	hp300_ptob
22162641Shibler #endif
22262641Shibler #endif
22362641Shibler 
22462641Shibler int is68040 = 0;
22562641Shibler 
22662641Shibler /*
22762641Shibler  * When looking at kernel data space through /dev/mem or
22862641Shibler  * with a core file, do virtual memory mapping.
22962641Shibler  */
vtophys(addr)23062641Shibler vtophys(addr)
23162641Shibler 	off_t addr;
23262641Shibler {
23362641Shibler 	int v;
23462641Shibler 	struct pte pte;
23562641Shibler 	int oldaddr = addr;
23662641Shibler 
23762641Shibler 	if (INKERNEL(addr)) {
23862641Shibler 		/*
23962641Shibler 		 * In system space get system pte.  If
24062641Shibler 		 * valid or reclaimable then physical address
24162641Shibler 		 * is combination of its page number and the page
24262641Shibler 		 * offset of the original address.
24362641Shibler 		 */
24462641Shibler #ifdef NEWVM
24562641Shibler 		/* locate PTE page in segtab */
24662641Shibler 		if (is68040) {
24762641Shibler 			int steaddr;
24862641Shibler 
24962641Shibler 			steaddr = KVTOPH((int)(sbr+(addr>>SG4_SHIFT1)));
25062641Shibler 			lseek(fcor, (off_t)steaddr, 0);
25162641Shibler 			read(fcor, &pte, sizeof pte);
25262641Shibler #if 0
25362641Shibler 			printf("va %X: ste1 %X@%X",
25462641Shibler 			       addr, *(int *)&pte, steaddr);
25562641Shibler #endif
25662641Shibler 			if (*(int *)&pte == SG_NV)
25762641Shibler 				goto bad;
25862641Shibler 			steaddr = (int)(((int *)(*(int *)&pte & SG4_ADDR1)) +
25962641Shibler 					((addr & SG4_MASK2) >> SG4_SHIFT2));
26062641Shibler 			physrw(fcor, steaddr, (int *)&pte, 1);
26162641Shibler #if 0
26262641Shibler 			printf(" ste2 %X@%X", *(int *)&pte, steaddr);
26362641Shibler #endif
26462641Shibler 		} else {
26562641Shibler 			lseek(fcor,
26662641Shibler 			      (off_t)KVTOPH((int)(sbr+(addr>>SG_ISHIFT))), 0);
26762641Shibler 			read(fcor, &pte, sizeof pte);
26862641Shibler #if 0
26962641Shibler 			printf("va %X: ste %X@%X",
27062641Shibler 			       addr, *(int *)&pte, sbr+(addr>>SG_ISHIFT));
27162641Shibler #endif
27262641Shibler 		}
27362641Shibler 		/* see if STE is valid */
27462641Shibler 		if (*(int *)&pte == SG_NV) {
27562641Shibler bad:
27662641Shibler 			errflg = "address out of segment";
27762641Shibler 			return(-1);
27862641Shibler 		}
27962641Shibler 		/* desired PTE is within that page */
28062641Shibler 		v = btop(addr & SG_PMASK);
28162641Shibler 		addr = (pte.pg_pfnum << PGSHIFT) + (v * sizeof pte);
28262641Shibler #else
28362641Shibler 		v = btop(addr - KERNOFF);
28462641Shibler 		addr = (long)(sbr+v) + lowram;
28562641Shibler #endif
28662641Shibler 	}
28762641Shibler 	else if (INUDOT(addr)) {
28862641Shibler 		addr -= kernudot;
28962641Shibler 		addr += masterpcbb;
29062641Shibler 		return(vtophys(addr));
29162641Shibler 	}
29262641Shibler 	else /* user space */ {
29362641Shibler #ifdef NEWVM
29462641Shibler 		errflg = "cannot translate user addresses";
29562641Shibler 		return (-1);
29662641Shibler #else
29762641Shibler 		v = btop(addr);
29862641Shibler 		/*
29962641Shibler 		 * Must be within bounds of p0 or p1 regions.
30062641Shibler 		 */
30162641Shibler 		if (v < pcb.pcb_p0lr)
30262641Shibler 			addr = pcb.pcb_p0br+v;
30362641Shibler 		else if (v >= pcb.pcb_p1lr)
30462641Shibler 			addr = pcb.pcb_p1br+v;
30562641Shibler 		else {
30662641Shibler 			errflg = "address out of segment";
30762641Shibler 			return (-1);
30862641Shibler 		}
30962641Shibler 		/*
31062641Shibler 		 * For p0/p1 address, user-level page table should
31162641Shibler 		 * be in kernel vm.  Do second-level indirect by recursing.
31262641Shibler 		 */
31362641Shibler 		if (!INKERNEL(addr)) {
31462641Shibler 			errflg = "bad p0br or p1br in pcb";
31562641Shibler 			return (-1);
31662641Shibler 		}
31762641Shibler 		addr = vtophys(addr);
31862641Shibler #endif
31962641Shibler 	}
32062641Shibler 	/*
32162641Shibler 	 * Addr is now address of the pte of the page we
32262641Shibler 	 * are interested in; get the pte and paste up the
32362641Shibler 	 * physical address.
32462641Shibler 	 */
32562641Shibler 	if (physrw(fcor, addr, (int *)&pte, 1) < 0) {
32662641Shibler 		errflg = "page table botch";
32762641Shibler 		return (-1);
32862641Shibler 	}
32962641Shibler 	if (pte.pg_v == 0 &&
33062641Shibler #ifdef NEWVM
33162641Shibler 	    pte.pg_pfnum == 0
33262641Shibler #else
33362641Shibler 	    (pte.pg_fod || pte.pg_pfnum == 0)
33462641Shibler #endif
33562641Shibler 	) {
33662641Shibler 		errflg = "page not valid/reclaimable";
33762641Shibler 		return (-1);
33862641Shibler 	}
33962641Shibler #if 0
34062641Shibler 	printf(" -> pte %X@%X -> addr %X\n",
34162641Shibler 	       *(int *)&pte, addr, ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
34262641Shibler #endif
34362641Shibler 	return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
34462641Shibler }
34562641Shibler #endif
34662641Shibler 
34762641Shibler #if !vax && !hp300
34862641Shibler help!
34962641Shibler #endif
35062641Shibler 
rwerr(space)35162641Shibler rwerr(space)
35262641Shibler 	int space;
35362641Shibler {
35462641Shibler 
35562641Shibler 	if (space & DSP)
35662641Shibler 		errflg = "data address not found";
35762641Shibler 	else if (space & PSP)
35862641Shibler 		errflg = "physical address not found";
35962641Shibler 	else
36062641Shibler 		errflg = "text address not found";
36162641Shibler }
36262641Shibler 
physrw(file,addr,aw,rd)36362641Shibler physrw(file, addr, aw, rd)
36462641Shibler 	off_t addr;
36562641Shibler 	int *aw, rd;
36662641Shibler {
36762641Shibler 
36862641Shibler #ifdef hp300
36962641Shibler 	if (kcore && !kmem && file == fcor)
37062641Shibler 		addr -= lowram;
37162641Shibler #endif
37262641Shibler 	if (longseek(file,addr)==0 ||
37362641Shibler 	    (rd ? read(file,aw,sizeof(int)) : write(file,aw,sizeof(int))) < 1)
37462641Shibler 		return (-1);
37562641Shibler 	return (0);
37662641Shibler }
37762641Shibler 
chkmap(addr,space)37862641Shibler chkmap(addr,space)
37962641Shibler 	REG L_INT	*addr;
38062641Shibler 	REG INT		space;
38162641Shibler {
38262641Shibler 	REG MAPPTR amap;
38362641Shibler 	amap = mapptr(space);
38462641Shibler 	IF space&STAR ORF !within(*addr,amap->b1,amap->e1)
38562641Shibler 	THEN IF within(*addr,amap->b2,amap->e2)
38662641Shibler 	     THEN *addr += (amap->f2)-(amap->b2);
38762641Shibler 	     ELSE rwerr(space); return(0);
38862641Shibler 	     FI
38962641Shibler 	ELSE *addr += (amap->f1)-(amap->b1);
39062641Shibler 	FI
39162641Shibler 	return(1);
39262641Shibler }
39362641Shibler 
within(addr,lbd,ubd)39462641Shibler within(addr,lbd,ubd)
39562641Shibler     u_int addr, lbd, ubd; { return(addr>=lbd && addr<ubd); }
39662641Shibler 
longseek(f,a)39762641Shibler longseek(f, a)
39862641Shibler     off_t a; { return(lseek(f, a, 0) != -1); }
399*62649Shibler 
400*62649Shibler #ifdef NEWVM
401*62649Shibler #undef lseek
402*62649Shibler #undef off_t
Lseek(f,o,w)403*62649Shibler Lseek(f, o, w)
404*62649Shibler     int f, w; Ooff_t o; { return(lseek(f, (off_t)o, w)); }
405*62649Shibler #endif
406