Home | History | Annotate | Line # | Download | only in libkvm
      1 /*	$NetBSD: kvm_powerpc.c,v 1.15 2023/08/23 14:00:11 rin Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005 Wasabi Systems, Inc.
      5  * All rights reserved.
      6  *
      7  * Written by Allen Briggs for Wasabi Systems, Inc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *      This product includes software developed for the NetBSD Project by
     20  *      Wasabi Systems, Inc.
     21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22  *    or promote products derived from this software without specific prior
     23  *    written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  * POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 /*-
     38  * Copyright (C) 1996 Wolfgang Solfrank.
     39  * Copyright (C) 1996 TooLs GmbH.
     40  * All rights reserved.
     41  *
     42  * Redistribution and use in source and binary forms, with or without
     43  * modification, are permitted provided that the following conditions
     44  * are met:
     45  * 1. Redistributions of source code must retain the above copyright
     46  *    notice, this list of conditions and the following disclaimer.
     47  * 2. Redistributions in binary form must reproduce the above copyright
     48  *    notice, this list of conditions and the following disclaimer in the
     49  *    documentation and/or other materials provided with the distribution.
     50  * 3. All advertising materials mentioning features or use of this software
     51  *    must display the following acknowledgement:
     52  *	This product includes software developed by TooLs GmbH.
     53  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     54  *    derived from this software without specific prior written permission.
     55  *
     56  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     57  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     58  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     59  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     60  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     61  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     62  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     63  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     64  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     65  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     66  */
     67 
     68 /*
     69  * PowerPC machine dependent routines for kvm.
     70  */
     71 
     72 #include <sys/param.h>
     73 #include <sys/exec.h>
     74 #include <sys/types.h>
     75 
     76 #include <uvm/uvm_extern.h>
     77 
     78 #include <db.h>
     79 #include <limits.h>
     80 #include <kvm.h>
     81 #include <stdlib.h>
     82 #include <unistd.h>
     83 
     84 #include "kvm_private.h"
     85 
     86 #include <sys/kcore.h>
     87 #include <machine/kcore.h>
     88 
     89 #include <powerpc/spr.h>
     90 #include <powerpc/oea/spr.h>
     91 #include <powerpc/oea/bat.h>
     92 #include <powerpc/oea/pte.h>
     93 
     94 __RCSID("$NetBSD: kvm_powerpc.c,v 1.15 2023/08/23 14:00:11 rin Exp $");
     95 
     96 static int	_kvm_match_601bat(kvm_t *, vaddr_t, paddr_t *, int *);
     97 static int	_kvm_match_bat(kvm_t *, vaddr_t, paddr_t *, int *);
     98 static int	_kvm_match_sr(kvm_t *, vaddr_t, paddr_t *, int *);
     99 static struct pte *_kvm_scan_pteg(struct pteg *, uint32_t, uint32_t, int);
    100 
    101 void
    102 _kvm_freevtop(kvm_t *kd)
    103 {
    104 	if (kd->vmst != 0)
    105 		free(kd->vmst);
    106 }
    107 
    108 /*ARGSUSED*/
    109 int
    110 _kvm_initvtop(kvm_t *kd)
    111 {
    112 
    113 	return 0;
    114 }
    115 
    116 #define BAT601_SIZE(b)  ((((b) << 17) | ~BAT601_BLPI) + 1)
    117 
    118 static int
    119 _kvm_match_601bat(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off)
    120 {
    121 	cpu_kcore_hdr_t	*cpu_kh;
    122 	u_long		pgoff;
    123 	size_t		size;
    124 	int		i, nbat;
    125 
    126 	cpu_kh = kd->cpu_data;
    127 	nbat = 4;
    128 	for (i=0 ; i<nbat ; i++) {
    129 		if (!BAT601_VALID_P(cpu_kh->dbatu[i]))
    130 			continue;
    131 		if (BAT601_VA_MATCH_P(cpu_kh->dbatu[i], cpu_kh->dbatl[i], va)) {
    132 			size = BAT601_SIZE(cpu_kh->dbatu[i] & BAT601_BSM);
    133 			pgoff = va & (size-1);
    134 			*pa = (cpu_kh->dbatl[i] & BAT601_PBN) + pgoff;
    135 			*off = size - pgoff;
    136 			return 1;
    137 		}
    138 	}
    139 	return 0;
    140 }
    141 
    142 #undef BAT601_SIZE
    143 
    144 #define BAT_SIZE(b)     ((((b) << 15) | ~BAT_EPI) + 1)
    145 
    146 static int
    147 _kvm_match_bat(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off)
    148 {
    149 	cpu_kcore_hdr_t	*cpu_kh;
    150 	u_long		pgoff;
    151 	size_t		size;
    152 	int		i, nbat;
    153 
    154 	cpu_kh = kd->cpu_data;
    155 	/*
    156 	 * Assume that we're looking for data and check only the dbats.
    157 	 */
    158 	nbat = 8;
    159 	for (i=0 ; i<nbat ; i++) {
    160 		if (   ((cpu_kh->dbatu[i] & BAT_Vs) != 0)
    161 		    && (BAT_VA_MATCH_P(cpu_kh->dbatu[i], va))) {
    162 			size = BAT_SIZE(cpu_kh->dbatu[i] & BAT_BL);
    163 			pgoff = va & (size-1);
    164 			*pa = (cpu_kh->dbatl[i] & BAT_RPN) + pgoff;
    165 			*off = size - pgoff;
    166 			return 1;
    167 		}
    168 	}
    169 	return 0;
    170 }
    171 
    172 #undef BAT_SIZE
    173 
    174 #define SR_VSID_HASH_MASK	0x0007ffff
    175 
    176 static struct pte *
    177 _kvm_scan_pteg(struct pteg *pteg, uint32_t vsid, uint32_t api, int secondary)
    178 {
    179 	struct pte	*pte;
    180 	u_long		ptehi;
    181 	int		i;
    182 
    183 	for (i=0 ; i<8 ; i++) {
    184 		pte = &pteg->pt[i];
    185 		ptehi = (u_long) pte->pte_hi;
    186 		if ((ptehi & PTE_VALID) == 0)
    187 			continue;
    188 		if ((ptehi & PTE_HID) != secondary)
    189 			continue;
    190 		if (((ptehi & PTE_VSID) >> PTE_VSID_SHFT) != vsid)
    191 			continue;
    192 		if (((ptehi & PTE_API) >> PTE_API_SHFT) != api)
    193 			continue;
    194 		return pte;
    195 	}
    196 	return NULL;
    197 }
    198 
    199 #define HASH_MASK	0x0007ffff
    200 
    201 static int
    202 _kvm_match_sr(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off)
    203 {
    204 	cpu_kcore_hdr_t	*cpu_kh;
    205 	struct pteg	pteg;
    206 	struct pte	*pte;
    207 	uint32_t	sr, pgoff, vsid, pgidx, api, hash;
    208 	uint32_t	htaborg, htabmask, mhash;
    209 	paddr_t		pteg_vaddr;
    210 
    211 	cpu_kh = kd->cpu_data;
    212 
    213 	sr = cpu_kh->sr[(va >> 28) & 0xf];
    214 	if ((sr & SR_TYPE) != 0) {
    215 		/* Direct-store segment (shouldn't be) */
    216 		return 0;
    217 	}
    218 
    219 	pgoff = va & ADDR_POFF;
    220 	vsid = sr & SR_VSID;
    221 	pgidx = (va & ADDR_PIDX) >> ADDR_PIDX_SHFT;
    222 	api = pgidx >> 10;
    223 	hash = (vsid & HASH_MASK) ^ pgidx;
    224 
    225 	htaborg = cpu_kh->sdr1 & 0xffff0000;
    226 	htabmask = cpu_kh->sdr1 & 0x1ff;
    227 
    228 	mhash = (hash >> 10) & htabmask;
    229 
    230 	pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6)
    231 		   | ((htaborg & 0x01ff0000) | (mhash << 16));
    232 
    233 	if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg),
    234 		  _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) {
    235 		_kvm_syserr(kd, 0, "could not read primary PTEG");
    236 		return 0;
    237 	}
    238 
    239 	if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) {
    240 		*pa = (pte->pte_lo & PTE_RPGN) | pgoff;
    241 		*off = NBPG - pgoff;
    242 		return 1;
    243 	}
    244 
    245 	hash = (~hash) & HASH_MASK;
    246 	mhash = (hash >> 10) & htabmask;
    247 
    248 	pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6)
    249 		   | ((htaborg & 0x01ff0000) | (mhash << 16));
    250 
    251 	if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg),
    252 		  _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) {
    253 		_kvm_syserr(kd, 0, "could not read secondary PTEG");
    254 		return 0;
    255 	}
    256 
    257 	if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) {
    258 		*pa = (pte->pte_lo & PTE_RPGN) | pgoff;
    259 		*off = NBPG - pgoff;
    260 		return 1;
    261 	}
    262 
    263 	return 0;
    264 }
    265 
    266 /*
    267  * Translate a KVA to a PA
    268  */
    269 int
    270 _kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa)
    271 {
    272 	cpu_kcore_hdr_t	*cpu_kh;
    273 	int		offs;
    274 	uint32_t	pvr;
    275 
    276 	if (ISALIVE(kd)) {
    277 		_kvm_err(kd, 0, "vatop called in live kernel!");
    278 		return 0;
    279 	}
    280 
    281 	cpu_kh = kd->cpu_data;
    282 
    283 	pvr = (cpu_kh->pvr >> 16);
    284 	if (MPC745X_P(pvr))
    285 		pvr = MPC7450;
    286 
    287 	switch (pvr) {
    288 	case MPC601:
    289 		/* Check for a BAT hit first */
    290 		if (_kvm_match_601bat(kd, va, pa, &offs)) {
    291 			return offs;
    292 		}
    293 
    294 		/* No BAT hit; check page tables */
    295 		if (_kvm_match_sr(kd, va, pa, &offs)) {
    296 			return offs;
    297 		}
    298 		break;
    299 
    300 	case MPC603:
    301 	case MPC603e:
    302 	case MPC603ev:
    303 	case MPC604:
    304 	case MPC604ev:
    305 	case MPC750:
    306 	case IBM750FX:
    307 	case MPC7400:
    308 	case MPC7450:
    309 	case MPC7410:
    310 	case MPC8240:
    311 	case MPC8245:
    312 		/* Check for a BAT hit first */
    313 		if (_kvm_match_bat(kd, va, pa, &offs)) {
    314 			return offs;
    315 		}
    316 
    317 		/* No BAT hit; check page tables */
    318 		if (_kvm_match_sr(kd, va, pa, &offs)) {
    319 			return offs;
    320 		}
    321 		break;
    322 
    323 	default:
    324 		_kvm_err(kd, 0, "Unsupported CPU type (pvr 0x%08lx)!",
    325 		    (unsigned long) cpu_kh->pvr);
    326 		break;
    327 	}
    328 
    329 	/* No hit -- no translation */
    330 	*pa = (paddr_t)~0UL;
    331 	return 0;
    332 }
    333 
    334 off_t
    335 _kvm_pa2off(kvm_t *kd, paddr_t pa)
    336 {
    337 	cpu_kcore_hdr_t	*cpu_kh;
    338 	phys_ram_seg_t	*ram;
    339 	off_t		off;
    340 	void		*e;
    341 
    342 	cpu_kh = kd->cpu_data;
    343 	e = (char *) kd->cpu_data + kd->cpu_dsize;
    344 	ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh));
    345 	off = kd->dump_off;
    346 	do {
    347 		if (pa >= ram->start && (pa - ram->start) < ram->size) {
    348 			return off + (pa - ram->start);
    349 		}
    350 		ram++;
    351 		off += ram->size;
    352 	} while ((void *) ram < e && ram->size);
    353 
    354 	_kvm_err(kd, 0, "pa2off failed for pa %#" PRIxPADDR "\n", pa);
    355 	return (off_t) -1;
    356 }
    357 
    358 /*
    359  * Machine-dependent initialization for ALL open kvm descriptors,
    360  * not just those for a kernel crash dump.  Some architectures
    361  * have to deal with these NOT being constants!  (i.e. m68k)
    362  */
    363 int
    364 _kvm_mdopen(kvm_t *kd)
    365 {
    366 	uintptr_t max_uva;
    367 	extern struct ps_strings *__ps_strings;
    368 
    369 #if 0   /* XXX - These vary across powerpc machines... */
    370 	kd->min_uva = VM_MIN_ADDRESS;
    371 	kd->max_uva = VM_MAXUSER_ADDRESS;
    372 #endif
    373 	/* This is somewhat hack-ish, but it works. */
    374 	max_uva = (uintptr_t) (__ps_strings + 1);
    375 	kd->max_uva  = max_uva;
    376 	kd->min_uva  = 0;
    377 
    378 	return (0);
    379 }
    380