1 #ifndef lint 2 static char sccsid[] = "@(#)access.c 4.8 10/13/84"; 3 #endif 4 /* 5 * Adb: access data in file/process address space. 6 * 7 * The routines in this file access referenced data using 8 * the maps to access files, ptrace to access subprocesses, 9 * or the system page tables when debugging the kernel, 10 * to translate virtual to physical addresses. 11 */ 12 13 #include "defs.h" 14 15 16 MAP txtmap; 17 MAP datmap; 18 INT wtflag; 19 STRING errflg; 20 int errno; 21 22 INT pid; 23 24 /* 25 * Primitives: put a value in a space, get a value from a space 26 * and get a word or byte not returning if an error occurred. 27 */ 28 put(addr, space, value) 29 off_t addr; { (void) access(WT, addr, space, value); } 30 31 #if vax || pdp11 32 u_int 33 get(addr, space) 34 off_t addr; { return (access(RD, addr, space, 0)); } 35 36 u_int 37 lchkget(addr, space) 38 off_t addr; { u_int w = get(addr, space); chkerr(); return(w); } 39 #endif 40 41 #ifdef mc68000 42 /* 43 * 68000 Unices don't like odd addresses. 44 */ 45 u_int 46 get(addr, space) 47 off_t addr; 48 { 49 u_int data; 50 51 if (addr & 1) { 52 data = access(RD, addr - 1, space, 0); 53 return ((data >> 8) & 0xffff); 54 } 55 data = access(RD, addr, space, 0); 56 return ((data >> 16) & 0xffff); 57 } 58 59 u_int 60 lget(addr, space) 61 off_t addr; 62 { 63 if (addr & 1) { 64 u_int data = get(addr, space); 65 return (get(addr + 2, space) | (data << 16)); 66 } 67 return (access(RD, addr, space, 0)); 68 } 69 70 u_int 71 lchkget(addr, space) 72 off_t addr; { u_int w = lget(addr, space); chkerr(); return(w); } 73 #endif 74 75 #if !pdp11 && !vax && !mc68000 76 help! 77 #endif 78 79 u_int 80 chkget(addr, space) 81 off_t addr; { u_int w = get(addr, space); chkerr(); return(w); } 82 83 u_int 84 bchkget(addr, space) 85 off_t addr; { return(lobyte(chkget(addr, space))); } 86 87 /* 88 * Read/write according to mode at address addr in i/d space. 89 * Value is quantity to be written, if write. 90 * 91 * This routine decides whether to get the data from the subprocess 92 * address space with ptrace, or to get it from the files being 93 * debugged. 94 * 95 * When the kernel is being debugged with the -k flag we interpret 96 * the system page tables for data space, mapping p0 and p1 addresses 97 * relative to the ``current'' process (as specified by its p_addr in 98 * <p) and mapping system space addresses through the system page tables. 99 */ 100 access(mode, addr, space, value) 101 int mode, space, value; 102 off_t addr; 103 { 104 int rd = mode == RD; 105 int file, w; 106 107 if (space == NSP) 108 return(0); 109 if (pid) { 110 int pmode = (space&DSP ? 111 (rd ? PT_READ_D : PT_WRITE_D) : 112 (rd ? PT_READ_I : PT_WRITE_I)); 113 114 w = ptrace(pmode, pid, addr, value); 115 if (errno) 116 rwerr(space); 117 return (w); 118 } 119 w = 0; 120 if (mode==WT && wtflag==0) 121 error("not in write mode"); 122 if (!chkmap(&addr, space)) 123 return (0); 124 file = mapptr(space)->ufd; 125 if (kernel && space == DSP) { 126 addr = vtophys(addr); 127 if (addr == -1) 128 return (0); 129 } 130 if (physrw(file, addr, rd ? &w : &value, rd) < 0) 131 rwerr(space); 132 return (w); 133 } 134 135 #ifdef vax 136 /* 137 * When looking at kernel data space through /dev/mem or 138 * with a core file, do virtual memory mapping. 139 */ 140 vtophys(addr) 141 off_t addr; 142 { 143 int oldaddr = addr; 144 int v; 145 struct pte pte; 146 147 addr &= ~0xc0000000; 148 v = btop(addr); 149 switch (oldaddr&0xc0000000) { 150 151 case 0xc0000000: 152 case 0x80000000: 153 /* 154 * In system space get system pte. If 155 * valid or reclaimable then physical address 156 * is combination of its page number and the page 157 * offset of the original address. 158 */ 159 if (v >= slr) 160 goto oor; 161 addr = ((long)(sbr+v)) &~ 0x80000000; 162 goto simple; 163 164 case 0x40000000: 165 /* 166 * In p1 space must not be in shadow region. 167 */ 168 if (v < pcb.pcb_p1lr) 169 goto oor; 170 addr = pcb.pcb_p1br+v; 171 break; 172 173 case 0x00000000: 174 /* 175 * In p0 space must not be off end of region. 176 */ 177 if (v >= pcb.pcb_p0lr) 178 goto oor; 179 addr = pcb.pcb_p0br+v; 180 break; 181 oor: 182 errflg = "address out of segment"; 183 return (-1); 184 } 185 /* 186 * For p0/p1 address, user-level page table should 187 * be in kernel vm. Do second-level indirect by recursing. 188 */ 189 if ((addr & 0x80000000) == 0) { 190 errflg = "bad p0br or p1br in pcb"; 191 return (-1); 192 } 193 addr = vtophys(addr); 194 simple: 195 /* 196 * Addr is now address of the pte of the page we 197 * are interested in; get the pte and paste up the 198 * physical address. 199 */ 200 if (physrw(fcor, addr, (int *)&pte, 1) < 0) { 201 errflg = "page table botch"; 202 return (-1); 203 } 204 /* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */ 205 if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) { 206 errflg = "page not valid/reclaimable"; 207 return (-1); 208 } 209 return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)); 210 } 211 #endif 212 213 #ifdef hp300 214 215 #ifdef NEWVM 216 #ifndef btop 217 #define btop hp300_btop 218 #endif 219 #ifndef ptob 220 #define ptob hp300_ptob 221 #endif 222 #endif 223 224 int is68040 = 0; 225 226 /* 227 * When looking at kernel data space through /dev/mem or 228 * with a core file, do virtual memory mapping. 229 */ 230 vtophys(addr) 231 off_t addr; 232 { 233 int v; 234 struct pte pte; 235 int oldaddr = addr; 236 237 if (INKERNEL(addr)) { 238 /* 239 * In system space get system pte. If 240 * valid or reclaimable then physical address 241 * is combination of its page number and the page 242 * offset of the original address. 243 */ 244 #ifdef NEWVM 245 /* locate PTE page in segtab */ 246 if (is68040) { 247 int steaddr; 248 249 steaddr = KVTOPH((int)(sbr+(addr>>SG4_SHIFT1))); 250 lseek(fcor, (off_t)steaddr, 0); 251 read(fcor, &pte, sizeof pte); 252 #if 0 253 printf("va %X: ste1 %X@%X", 254 addr, *(int *)&pte, steaddr); 255 #endif 256 if (*(int *)&pte == SG_NV) 257 goto bad; 258 steaddr = (int)(((int *)(*(int *)&pte & SG4_ADDR1)) + 259 ((addr & SG4_MASK2) >> SG4_SHIFT2)); 260 physrw(fcor, steaddr, (int *)&pte, 1); 261 #if 0 262 printf(" ste2 %X@%X", *(int *)&pte, steaddr); 263 #endif 264 } else { 265 lseek(fcor, 266 (off_t)KVTOPH((int)(sbr+(addr>>SG_ISHIFT))), 0); 267 read(fcor, &pte, sizeof pte); 268 #if 0 269 printf("va %X: ste %X@%X", 270 addr, *(int *)&pte, sbr+(addr>>SG_ISHIFT)); 271 #endif 272 } 273 /* see if STE is valid */ 274 if (*(int *)&pte == SG_NV) { 275 bad: 276 errflg = "address out of segment"; 277 return(-1); 278 } 279 /* desired PTE is within that page */ 280 v = btop(addr & SG_PMASK); 281 addr = (pte.pg_pfnum << PGSHIFT) + (v * sizeof pte); 282 #else 283 v = btop(addr - KERNOFF); 284 addr = (long)(sbr+v) + lowram; 285 #endif 286 } 287 else if (INUDOT(addr)) { 288 addr -= kernudot; 289 addr += masterpcbb; 290 return(vtophys(addr)); 291 } 292 else /* user space */ { 293 #ifdef NEWVM 294 errflg = "cannot translate user addresses"; 295 return (-1); 296 #else 297 v = btop(addr); 298 /* 299 * Must be within bounds of p0 or p1 regions. 300 */ 301 if (v < pcb.pcb_p0lr) 302 addr = pcb.pcb_p0br+v; 303 else if (v >= pcb.pcb_p1lr) 304 addr = pcb.pcb_p1br+v; 305 else { 306 errflg = "address out of segment"; 307 return (-1); 308 } 309 /* 310 * For p0/p1 address, user-level page table should 311 * be in kernel vm. Do second-level indirect by recursing. 312 */ 313 if (!INKERNEL(addr)) { 314 errflg = "bad p0br or p1br in pcb"; 315 return (-1); 316 } 317 addr = vtophys(addr); 318 #endif 319 } 320 /* 321 * Addr is now address of the pte of the page we 322 * are interested in; get the pte and paste up the 323 * physical address. 324 */ 325 if (physrw(fcor, addr, (int *)&pte, 1) < 0) { 326 errflg = "page table botch"; 327 return (-1); 328 } 329 if (pte.pg_v == 0 && 330 #ifdef NEWVM 331 pte.pg_pfnum == 0 332 #else 333 (pte.pg_fod || pte.pg_pfnum == 0) 334 #endif 335 ) { 336 errflg = "page not valid/reclaimable"; 337 return (-1); 338 } 339 #if 0 340 printf(" -> pte %X@%X -> addr %X\n", 341 *(int *)&pte, addr, ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)); 342 #endif 343 return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)); 344 } 345 #endif 346 347 #if !vax && !hp300 348 help! 349 #endif 350 351 rwerr(space) 352 int space; 353 { 354 355 if (space & DSP) 356 errflg = "data address not found"; 357 else if (space & PSP) 358 errflg = "physical address not found"; 359 else 360 errflg = "text address not found"; 361 } 362 363 physrw(file, addr, aw, rd) 364 off_t addr; 365 int *aw, rd; 366 { 367 368 #ifdef hp300 369 if (kcore && !kmem && file == fcor) 370 addr -= lowram; 371 #endif 372 if (longseek(file,addr)==0 || 373 (rd ? read(file,aw,sizeof(int)) : write(file,aw,sizeof(int))) < 1) 374 return (-1); 375 return (0); 376 } 377 378 chkmap(addr,space) 379 REG L_INT *addr; 380 REG INT space; 381 { 382 REG MAPPTR amap; 383 amap = mapptr(space); 384 IF space&STAR ORF !within(*addr,amap->b1,amap->e1) 385 THEN IF within(*addr,amap->b2,amap->e2) 386 THEN *addr += (amap->f2)-(amap->b2); 387 ELSE rwerr(space); return(0); 388 FI 389 ELSE *addr += (amap->f1)-(amap->b1); 390 FI 391 return(1); 392 } 393 394 within(addr,lbd,ubd) 395 u_int addr, lbd, ubd; { return(addr>=lbd && addr<ubd); } 396 397 longseek(f, a) 398 off_t a; { return(lseek(f, a, 0) != -1); } 399 400 #ifdef NEWVM 401 #undef lseek 402 #undef off_t 403 Lseek(f, o, w) 404 int f, w; Ooff_t o; { return(lseek(f, (off_t)o, w)); } 405 #endif 406