Module Name: src Committed By: jym Date: Tue Oct 5 23:48:16 UTC 2010
Modified Files: src/lib/libkvm: Makefile kvm_i386.c src/sys/arch/i386/i386: dumpsys.c src/sys/arch/i386/include: kcore.h Added Files: src/lib/libkvm: kvm_i386pae.c Log Message: Import PAE support for kvm(3): - add kvm_i386pae.c (used for PAE memory translations), and update Makefile for libkvm build. - in pdppaddr: pass a flag to indicate PAE mode. Use a bit ignored by the MMU. Mask address with PG_FRAME to avoid side effects. Tested with vmstat(1)/netstat(1) to debug core files of PAE and !PAE kernels. Older kernel dumps will default to native i386 (!PAE) mode. XXX Currently, savecore(8) will fail to dump a PAE kernel in a !PAE environment (and reciprocally). So you need to sync and reboot with a kernel of the same mode as the one that crashed. Once the dump is successful, this does not matter anymore. To generate a diff of this commit: cvs rdiff -u -r1.45 -r1.46 src/lib/libkvm/Makefile cvs rdiff -u -r1.28 -r1.29 src/lib/libkvm/kvm_i386.c cvs rdiff -u -r0 -r1.1 src/lib/libkvm/kvm_i386pae.c cvs rdiff -u -r1.10 -r1.11 src/sys/arch/i386/i386/dumpsys.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/i386/include/kcore.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libkvm/Makefile diff -u src/lib/libkvm/Makefile:1.45 src/lib/libkvm/Makefile:1.46 --- src/lib/libkvm/Makefile:1.45 Sat Oct 25 23:59:42 2008 +++ src/lib/libkvm/Makefile Tue Oct 5 23:48:16 2010 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.45 2008/10/25 23:59:42 mrg Exp $ +# $NetBSD: Makefile,v 1.46 2010/10/05 23:48:16 jym Exp $ # from: @(#)Makefile 8.1 (Berkeley) 6/4/93 USE_FORT?= yes # used primarily by setgid programs @@ -7,9 +7,6 @@ LIB= kvm CPPFLAGS+=-DLIBC_SCCS -I${NETBSDSRCDIR}/sys -.if ${MACHINE_ARCH} == "i386" -LINTFLAGS+=-w -.endif SRCS= kvm.c kvm_file.c kvm_getloadavg.c kvm_proc.c @@ -31,6 +28,11 @@ @false .endif +.if ${MACHINE_ARCH} == "i386" +LINTFLAGS+=-w +SRCS+= kvm_i386pae.c # Hook PAE support in the i386 build +.endif + # Additional modules needed for m68k .if (${MACHINE_ARCH} == "m68k" || ${MACHINE_CPU} == "m68k") SRCS+= kvm_m68k_cmn.c kvm_sun2.c kvm_sun3.c kvm_sun3x.c Index: src/lib/libkvm/kvm_i386.c diff -u src/lib/libkvm/kvm_i386.c:1.28 src/lib/libkvm/kvm_i386.c:1.29 --- src/lib/libkvm/kvm_i386.c:1.28 Mon Sep 20 23:23:16 2010 +++ src/lib/libkvm/kvm_i386.c Tue Oct 5 23:48:16 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: kvm_i386.c,v 1.28 2010/09/20 23:23:16 jym Exp $ */ +/* $NetBSD: kvm_i386.c,v 1.29 2010/10/05 23:48:16 jym Exp $ */ /*- * Copyright (c) 1989, 1992, 1993 @@ -38,7 +38,7 @@ #if 0 static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: kvm_i386.c,v 1.28 2010/09/20 23:23:16 jym Exp $"); +__RCSID("$NetBSD: kvm_i386.c,v 1.29 2010/10/05 23:48:16 jym Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -74,6 +74,16 @@ #define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ #endif +/* + * Indicates whether PAE is in use for the kernel image + * 0: native i386 memory mappings + * 1: i386 PAE mappings + */ +static int i386_use_pae; + +int _kvm_kvatop_i386(kvm_t *, vaddr_t, paddr_t *); +int _kvm_kvatop_i386pae(kvm_t *, vaddr_t, paddr_t *); + void _kvm_freevtop(kvm_t *kd) { @@ -87,6 +97,11 @@ int _kvm_initvtop(kvm_t *kd) { + cpu_kcore_hdr_t *cpu_kh = kd->cpu_data; + + i386_use_pae = 0; /* default: non PAE mode */ + if ((cpu_kh->pdppaddr & I386_KCORE_PAE) == I386_KCORE_PAE) + i386_use_pae = 1; return 0; } @@ -97,24 +112,44 @@ int _kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) { - cpu_kcore_hdr_t *cpu_kh; - u_long page_off; - pd_entry_t pde; - pt_entry_t pte; - paddr_t pde_pa, pte_pa; if (ISALIVE(kd)) { _kvm_err(kd, 0, "vatop called in live kernel!"); return 0; } + switch (i386_use_pae) { + default: + case 0: + return _kvm_kvatop_i386(kd, va, pa); + case 1: + return _kvm_kvatop_i386pae(kd, va, pa); + } + +} + +/* + * Used to translate a virtual address to a physical address for systems + * with PAE mode disabled. Only two levels of virtual memory pages are + * dereferenced (L2 PDEs, then L1 PTEs). + */ +int +_kvm_kvatop_i386(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + cpu_kh = kd->cpu_data; page_off = va & PGOFSET; /* * Find and read the page directory entry. + * pdppaddr being PAGE_SIZE aligned, we mask the option bits. */ - pde_pa = cpu_kh->pdppaddr + (pl2_pi(va) * sizeof(pd_entry_t)); + pde_pa = (cpu_kh->pdppaddr & PG_FRAME) + (pl2_pi(va) * sizeof(pde)); if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { _kvm_syserr(kd, 0, "could not read PDE"); Index: src/sys/arch/i386/i386/dumpsys.c diff -u src/sys/arch/i386/i386/dumpsys.c:1.10 src/sys/arch/i386/i386/dumpsys.c:1.11 --- src/sys/arch/i386/i386/dumpsys.c:1.10 Sat Oct 2 22:54:47 2010 +++ src/sys/arch/i386/i386/dumpsys.c Tue Oct 5 23:48:16 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: dumpsys.c,v 1.10 2010/10/02 22:54:47 jym Exp $ */ +/* $NetBSD: dumpsys.c,v 1.11 2010/10/05 23:48:16 jym Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008 The NetBSD Foundation, Inc. @@ -69,7 +69,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: dumpsys.c,v 1.10 2010/10/02 22:54:47 jym Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dumpsys.c,v 1.11 2010/10/05 23:48:16 jym Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -628,6 +628,8 @@ * Add the machine-dependent header info. */ cpuhdr.pdppaddr = PDPpaddr; + if (i386_use_pae == 1) + cpuhdr.pdppaddr |= I386_KCORE_PAE; cpuhdr.nmemsegs = dump_nmemsegs; (void)dump_header_addbytes(&cpuhdr, ALIGN(sizeof(cpuhdr))); Index: src/sys/arch/i386/include/kcore.h diff -u src/sys/arch/i386/include/kcore.h:1.4 src/sys/arch/i386/include/kcore.h:1.5 --- src/sys/arch/i386/include/kcore.h:1.4 Sat Jan 12 20:03:42 2008 +++ src/sys/arch/i386/include/kcore.h Tue Oct 5 23:48:16 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: kcore.h,v 1.4 2008/01/12 20:03:42 ad Exp $ */ +/* $NetBSD: kcore.h,v 1.5 2010/10/05 23:48:16 jym Exp $ */ /* * Copyright (c) 1996 Carnegie-Mellon University. @@ -43,6 +43,15 @@ #endif } cpu_kcore_hdr_t; +/* + * Used to indicate that PAE should be used for virtual address + * translation. As PDPpaddr is expected to be PAGE_SIZE aligned, + * this can be safely OR'ed in pdppaddr. + * To avoid any kind of conflict with existing MMU bits, we chose one + * ignored by hardware + */ +#define I386_KCORE_PAE PG_AVAIL1 + #ifdef _KERNEL void dumpsys(void); Added files: Index: src/lib/libkvm/kvm_i386pae.c diff -u /dev/null src/lib/libkvm/kvm_i386pae.c:1.1 --- /dev/null Tue Oct 5 23:48:16 2010 +++ src/lib/libkvm/kvm_i386pae.c Tue Oct 5 23:48:16 2010 @@ -0,0 +1,131 @@ +/* $NetBSD: kvm_i386pae.c,v 1.1 2010/10/05 23:48:16 jym Exp $ */ + +/* + * Copyright (c) 2010 Jean-Yves Migeon. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: kvm_i386pae.c,v 1.1 2010/10/05 23:48:16 jym Exp $"); + +/* + * This will expose PAE functions, macros, definitions and constants. + * Note: this affects all virtual memory related functions. Only their + * PAE versions can be used below. + */ +#define PAE + +#include <sys/param.h> +#include <sys/user.h> +#include <sys/stat.h> +#include <sys/kcore.h> +#include <sys/types.h> + +#include <stdlib.h> +#include <unistd.h> +#include <nlist.h> +#include <kvm.h> + +#include <uvm/uvm_extern.h> + +#include <limits.h> +#include <db.h> + +#include "kvm_private.h" + +#include <i386/kcore.h> +#include <i386/pmap.h> +#include <i386/pte.h> +#include <i386/vmparam.h> + +int _kvm_kvatop_i386pae(kvm_t *, vaddr_t, paddr_t *); + +/* + * Used to translate a virtual address to a physical address for systems + * running under PAE mode. Three levels of virtual memory pages are handled + * here: the per-CPU L3 page, the 4 L2 PDs and the PTs. + */ +int +_kvm_kvatop_i386pae(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + + cpu_kh = kd->cpu_data; + page_off = va & PGOFSET; + + /* + * Find and read the PDE. Ignore the L3, as it is only a per-CPU + * page, not needed for kernel VA => PA translations. + * Remember that the 4 L2 pages are contiguous, so it is safe + * to increment pdppaddr to compute the address of the PDE. + * pdppaddr being PAGE_SIZE aligned, we mask the option bits. + */ + pde_pa = (cpu_kh->pdppaddr & PG_FRAME) + (pl2_pi(va) * sizeof(pde)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PDE"); + goto lose; + } + + /* + * Find and read the page table entry. + */ + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PDE)"); + goto lose; + } + if ((pde & PG_PS) != 0) { + /* + * This is a 2MB page. + */ + page_off = va & ((vaddr_t)~PG_LGFRAME); + *pa = (pde & PG_LGFRAME) + page_off; + return (int)(NBPD_L2 - page_off); + } + + pte_pa = (pde & PG_FRAME) + (pl1_pi(va) * sizeof(pt_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + + /* + * Validate the PTE and return the physical address. + */ + if ((pte & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + *pa = (pte & PG_FRAME) + page_off; + return (int)(NBPG - page_off); + +lose: + *pa = (paddr_t)~0L; + return 0; + +}