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