Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libkvm/kvm_i386.c
Show All 40 Lines | |||||
#endif /* LIBC_SCCS and not lint */ | #endif /* LIBC_SCCS and not lint */ | ||||
/* | /* | ||||
* i386 machine dependent routines for kvm. Hopefully, the forthcoming | * i386 machine dependent routines for kvm. Hopefully, the forthcoming | ||||
* vm code will one day obsolete this module. | * vm code will one day obsolete this module. | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/user.h> | #include <sys/endian.h> | ||||
#include <sys/proc.h> | #include <stdint.h> | ||||
#include <sys/stat.h> | |||||
#include <sys/mman.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <nlist.h> | |||||
#include <kvm.h> | #include <kvm.h> | ||||
#include <vm/vm.h> | #ifdef __i386__ | ||||
#include <vm/vm_param.h> | #include <machine/vmparam.h> /* For KERNBASE. */ | ||||
#endif | |||||
#include <machine/elf.h> | |||||
#include <limits.h> | #include <limits.h> | ||||
#include "kvm_private.h" | #include "kvm_private.h" | ||||
#include "kvm_i386.h" | |||||
#ifndef btop | |||||
#define btop(x) (i386_btop(x)) | |||||
#define ptob(x) (i386_ptob(x)) | |||||
#endif | |||||
#define PG_FRAME_PAE (~((uint64_t)PAGE_MASK)) | |||||
#define PDRSHIFT_PAE 21 | |||||
#define NPTEPG_PAE (PAGE_SIZE/sizeof(uint64_t)) | |||||
#define NBPDR_PAE (1<<PDRSHIFT_PAE) | |||||
/* minidump must be the first item! */ | |||||
struct vmstate { | struct vmstate { | ||||
int minidump; /* 1 = minidump mode */ | |||||
void *mmapbase; | |||||
size_t mmapsize; | |||||
void *PTD; | void *PTD; | ||||
int pae; | int pae; | ||||
size_t phnum; | |||||
GElf_Phdr *phdr; | |||||
}; | }; | ||||
/* | /* | ||||
* Map the ELF headers into the process' address space. We do this in two | |||||
* steps: first the ELF header itself and using that information the whole | |||||
* set of headers. | |||||
*/ | |||||
static int | |||||
_kvm_maphdrs(kvm_t *kd, size_t sz) | |||||
{ | |||||
struct vmstate *vm = kd->vmst; | |||||
/* munmap() previous mmap(). */ | |||||
if (vm->mmapbase != NULL) { | |||||
munmap(vm->mmapbase, vm->mmapsize); | |||||
vm->mmapbase = NULL; | |||||
} | |||||
vm->mmapsize = sz; | |||||
vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); | |||||
if (vm->mmapbase == MAP_FAILED) { | |||||
_kvm_err(kd, kd->program, "cannot mmap corefile"); | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Translate a physical memory address to a file-offset in the crash-dump. | * Translate a physical memory address to a file-offset in the crash-dump. | ||||
*/ | */ | ||||
static size_t | static size_t | ||||
_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) | _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) | ||||
{ | { | ||||
Elf_Ehdr *e = kd->vmst->mmapbase; | struct vmstate *vm = kd->vmst; | ||||
Elf_Phdr *p; | GElf_Phdr *p; | ||||
int n; | size_t n; | ||||
if (kd->rawdump) { | if (kd->rawdump) { | ||||
*ofs = pa; | *ofs = pa; | ||||
return (PAGE_SIZE - ((size_t)pa & PAGE_MASK)); | return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); | ||||
} | } | ||||
p = (Elf_Phdr*)((char*)e + e->e_phoff); | p = vm->phdr; | ||||
n = e->e_phnum; | n = vm->phnum; | ||||
while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) | while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) | ||||
p++, n--; | p++, n--; | ||||
if (n == 0) | if (n == 0) | ||||
return (0); | return (0); | ||||
*ofs = (pa - p->p_paddr) + p->p_offset; | *ofs = (pa - p->p_paddr) + p->p_offset; | ||||
return (PAGE_SIZE - ((size_t)pa & PAGE_MASK)); | return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); | ||||
} | } | ||||
void | static void | ||||
_kvm_freevtop(kvm_t *kd) | _i386_freevtop(kvm_t *kd) | ||||
{ | { | ||||
struct vmstate *vm = kd->vmst; | struct vmstate *vm = kd->vmst; | ||||
if (kd->vmst->minidump) | |||||
return (_kvm_minidump_freevtop(kd)); | |||||
if (vm->mmapbase != NULL) | |||||
munmap(vm->mmapbase, vm->mmapsize); | |||||
if (vm->PTD) | if (vm->PTD) | ||||
free(vm->PTD); | free(vm->PTD); | ||||
free(vm->phdr); | |||||
free(vm); | free(vm); | ||||
kd->vmst = NULL; | kd->vmst = NULL; | ||||
} | } | ||||
int | static int | ||||
_kvm_initvtop(kvm_t *kd) | _i386_probe(kvm_t *kd) | ||||
{ | { | ||||
struct nlist nl[2]; | |||||
u_long pa; | return (_kvm_probe_elf_kernel(kd, ELFCLASS32, EM_386) && | ||||
u_long kernbase; | !_kvm_is_minidump(kd)); | ||||
} | |||||
static int | |||||
_i386_initvtop(kvm_t *kd) | |||||
{ | |||||
struct kvm_nlist nl[2]; | |||||
i386_physaddr_t pa; | |||||
kvaddr_t kernbase; | |||||
char *PTD; | char *PTD; | ||||
Elf_Ehdr *ehdr; | |||||
size_t hdrsz; | |||||
int i; | int i; | ||||
char minihdr[8]; | |||||
if (!kd->rawdump && pread(kd->pmfd, &minihdr, 8, 0) == 8) | kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(struct vmstate)); | ||||
if (memcmp(&minihdr, "minidump", 8) == 0) | if (kd->vmst == NULL) { | ||||
return (_kvm_minidump_initvtop(kd)); | |||||
kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); | |||||
if (kd->vmst == 0) { | |||||
_kvm_err(kd, kd->program, "cannot allocate vm"); | _kvm_err(kd, kd->program, "cannot allocate vm"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
kd->vmst->PTD = 0; | kd->vmst->PTD = 0; | ||||
if (kd->rawdump == 0) { | if (kd->rawdump == 0) { | ||||
if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1) | if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum, | ||||
&kd->vmst->phdr) == -1) | |||||
return (-1); | return (-1); | ||||
ehdr = kd->vmst->mmapbase; | |||||
hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; | |||||
if (_kvm_maphdrs(kd, hdrsz) == -1) | |||||
return (-1); | |||||
} | } | ||||
nl[0].n_name = "kernbase"; | nl[0].n_name = "kernbase"; | ||||
nl[1].n_name = 0; | nl[1].n_name = 0; | ||||
if (kvm_nlist(kd, nl) != 0) | if (kvm_nlist2(kd, nl) != 0) { | ||||
#ifdef __i386__ | |||||
kernbase = KERNBASE; /* for old kernels */ | kernbase = KERNBASE; /* for old kernels */ | ||||
else | #else | ||||
_kvm_err(kd, kd->program, "cannot resolve kernbase"); | |||||
return (-1); | |||||
#endif | |||||
} else | |||||
kernbase = nl[0].n_value; | kernbase = nl[0].n_value; | ||||
nl[0].n_name = "IdlePDPT"; | nl[0].n_name = "IdlePDPT"; | ||||
nl[1].n_name = 0; | nl[1].n_name = 0; | ||||
if (kvm_nlist(kd, nl) == 0) { | if (kvm_nlist2(kd, nl) == 0) { | ||||
uint64_t pa64; | i386_physaddr_pae_t pa64; | ||||
if (kvm_read(kd, (nl[0].n_value - kernbase), &pa, | if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, | ||||
sizeof(pa)) != sizeof(pa)) { | sizeof(pa)) != sizeof(pa)) { | ||||
_kvm_err(kd, kd->program, "cannot read IdlePDPT"); | _kvm_err(kd, kd->program, "cannot read IdlePDPT"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
PTD = _kvm_malloc(kd, 4 * PAGE_SIZE); | pa = le32toh(pa); | ||||
PTD = _kvm_malloc(kd, 4 * I386_PAGE_SIZE); | |||||
for (i = 0; i < 4; i++) { | for (i = 0; i < 4; i++) { | ||||
if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64, | if (kvm_read2(kd, pa + (i * sizeof(pa64)), &pa64, | ||||
sizeof(pa64)) != sizeof(pa64)) { | sizeof(pa64)) != sizeof(pa64)) { | ||||
_kvm_err(kd, kd->program, "Cannot read PDPT"); | _kvm_err(kd, kd->program, "Cannot read PDPT"); | ||||
free(PTD); | free(PTD); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if (kvm_read(kd, pa64 & PG_FRAME_PAE, | pa64 = le64toh(pa64); | ||||
PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) { | if (kvm_read2(kd, pa64 & I386_PG_FRAME_PAE, | ||||
PTD + (i * I386_PAGE_SIZE), I386_PAGE_SIZE) != | |||||
I386_PAGE_SIZE) { | |||||
_kvm_err(kd, kd->program, "cannot read PDPT"); | _kvm_err(kd, kd->program, "cannot read PDPT"); | ||||
free(PTD); | free(PTD); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
kd->vmst->PTD = PTD; | kd->vmst->PTD = PTD; | ||||
kd->vmst->pae = 1; | kd->vmst->pae = 1; | ||||
} else { | } else { | ||||
nl[0].n_name = "IdlePTD"; | nl[0].n_name = "IdlePTD"; | ||||
nl[1].n_name = 0; | nl[1].n_name = 0; | ||||
if (kvm_nlist(kd, nl) != 0) { | if (kvm_nlist2(kd, nl) != 0) { | ||||
_kvm_err(kd, kd->program, "bad namelist"); | _kvm_err(kd, kd->program, "bad namelist"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if (kvm_read(kd, (nl[0].n_value - kernbase), &pa, | if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, | ||||
sizeof(pa)) != sizeof(pa)) { | sizeof(pa)) != sizeof(pa)) { | ||||
_kvm_err(kd, kd->program, "cannot read IdlePTD"); | _kvm_err(kd, kd->program, "cannot read IdlePTD"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
PTD = _kvm_malloc(kd, PAGE_SIZE); | pa = le32toh(pa); | ||||
if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) { | PTD = _kvm_malloc(kd, I386_PAGE_SIZE); | ||||
if (kvm_read2(kd, pa, PTD, I386_PAGE_SIZE) != I386_PAGE_SIZE) { | |||||
_kvm_err(kd, kd->program, "cannot read PTD"); | _kvm_err(kd, kd->program, "cannot read PTD"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
kd->vmst->PTD = PTD; | kd->vmst->PTD = PTD; | ||||
kd->vmst->pae = 0; | kd->vmst->pae = 0; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
_kvm_vatop(kvm_t *kd, u_long va, off_t *pa) | _i386_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) | ||||
{ | { | ||||
struct vmstate *vm; | struct vmstate *vm; | ||||
u_long offset; | i386_physaddr_t offset; | ||||
u_long pte_pa; | i386_physaddr_t pte_pa; | ||||
u_long pde_pa; | i386_pde_t pde; | ||||
pd_entry_t pde; | i386_pte_t pte; | ||||
pt_entry_t pte; | kvaddr_t pdeindex; | ||||
u_long pdeindex; | kvaddr_t pteindex; | ||||
u_long pteindex; | |||||
size_t s; | size_t s; | ||||
u_long a; | i386_physaddr_t a; | ||||
off_t ofs; | off_t ofs; | ||||
uint32_t *PTD; | i386_pde_t *PTD; | ||||
vm = kd->vmst; | vm = kd->vmst; | ||||
PTD = (uint32_t *)vm->PTD; | PTD = (i386_pde_t *)vm->PTD; | ||||
offset = va & (PAGE_SIZE - 1); | offset = va & I386_PAGE_MASK; | ||||
/* | /* | ||||
* If we are initializing (kernel page table descriptor pointer | * If we are initializing (kernel page table descriptor pointer | ||||
* not yet set) then return pa == va to avoid infinite recursion. | * not yet set) then return pa == va to avoid infinite recursion. | ||||
*/ | */ | ||||
if (PTD == 0) { | if (PTD == 0) { | ||||
s = _kvm_pa2off(kd, va, pa); | s = _kvm_pa2off(kd, va, pa); | ||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, | _kvm_err(kd, kd->program, | ||||
"_kvm_vatop: bootstrap data not in dump"); | "_i386_vatop: bootstrap data not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} else | } else | ||||
return (PAGE_SIZE - offset); | return (I386_PAGE_SIZE - offset); | ||||
} | } | ||||
pdeindex = va >> PDRSHIFT; | pdeindex = va >> I386_PDRSHIFT; | ||||
pde = PTD[pdeindex]; | pde = le32toh(PTD[pdeindex]); | ||||
if (((u_long)pde & PG_V) == 0) { | if ((pde & I386_PG_V) == 0) { | ||||
_kvm_err(kd, kd->program, "_kvm_vatop: pde not valid"); | _kvm_err(kd, kd->program, "_i386_vatop: pde not valid"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
if ((u_long)pde & PG_PS) { | if (pde & I386_PG_PS) { | ||||
/* | /* | ||||
* No second-level page table; ptd describes one 4MB page. | * No second-level page table; ptd describes one 4MB | ||||
* (We assume that the kernel wouldn't set PG_PS without enabling | * page. (We assume that the kernel wouldn't set | ||||
* it cr0). | * PG_PS without enabling it cr0). | ||||
*/ | */ | ||||
#define PAGE4M_MASK (NBPDR - 1) | offset = va & I386_PAGE_PS_MASK; | ||||
#define PG_FRAME4M (~PAGE4M_MASK) | a = (pde & I386_PG_PS_FRAME) + offset; | ||||
pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK); | s = _kvm_pa2off(kd, a, pa); | ||||
s = _kvm_pa2off(kd, pde_pa, &ofs); | |||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, | _kvm_err(kd, kd->program, | ||||
"_kvm_vatop: 4MB page address not in dump"); | "_i386_vatop: 4MB page address not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
*pa = ofs; | return (I386_NBPDR - offset); | ||||
return (NBPDR - (va & PAGE4M_MASK)); | |||||
} | } | ||||
pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1); | pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG - 1); | ||||
pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde)); | pte_pa = (pde & I386_PG_FRAME) + (pteindex * sizeof(pte)); | ||||
s = _kvm_pa2off(kd, pte_pa, &ofs); | s = _kvm_pa2off(kd, pte_pa, &ofs); | ||||
if (s < sizeof pte) { | if (s < sizeof(pte)) { | ||||
_kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); | _kvm_err(kd, kd->program, "_i386_vatop: pte_pa not found"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
/* XXX This has to be a physical address read, kvm_read is virtual */ | /* XXX This has to be a physical address read, kvm_read is virtual */ | ||||
if (lseek(kd->pmfd, ofs, 0) == -1) { | if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { | ||||
_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek"); | _kvm_syserr(kd, kd->program, "_i386_vatop: pread"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { | pte = le32toh(pte); | ||||
_kvm_syserr(kd, kd->program, "_kvm_vatop: read"); | if ((pte & I386_PG_V) == 0) { | ||||
goto invalid; | |||||
} | |||||
if (((u_long)pte & PG_V) == 0) { | |||||
_kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid"); | _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
a = ((u_long)pte & PG_FRAME) + offset; | a = (pte & I386_PG_FRAME) + offset; | ||||
s =_kvm_pa2off(kd, a, pa); | s = _kvm_pa2off(kd, a, pa); | ||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, "_kvm_vatop: address not in dump"); | _kvm_err(kd, kd->program, "_i386_vatop: address not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} else | } else | ||||
return (PAGE_SIZE - offset); | return (I386_PAGE_SIZE - offset); | ||||
invalid: | invalid: | ||||
_kvm_err(kd, 0, "invalid address (0x%lx)", va); | _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
_kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa) | _i386_vatop_pae(kvm_t *kd, kvaddr_t va, off_t *pa) | ||||
{ | { | ||||
struct vmstate *vm; | struct vmstate *vm; | ||||
uint64_t offset; | i386_physaddr_pae_t offset; | ||||
uint64_t pte_pa; | i386_physaddr_pae_t pte_pa; | ||||
uint64_t pde_pa; | i386_pde_pae_t pde; | ||||
uint64_t pde; | i386_pte_pae_t pte; | ||||
uint64_t pte; | kvaddr_t pdeindex; | ||||
u_long pdeindex; | kvaddr_t pteindex; | ||||
u_long pteindex; | |||||
size_t s; | size_t s; | ||||
uint64_t a; | i386_physaddr_pae_t a; | ||||
off_t ofs; | off_t ofs; | ||||
uint64_t *PTD; | i386_pde_pae_t *PTD; | ||||
vm = kd->vmst; | vm = kd->vmst; | ||||
PTD = (uint64_t *)vm->PTD; | PTD = (i386_pde_pae_t *)vm->PTD; | ||||
offset = va & (PAGE_SIZE - 1); | offset = va & I386_PAGE_MASK; | ||||
/* | /* | ||||
* If we are initializing (kernel page table descriptor pointer | * If we are initializing (kernel page table descriptor pointer | ||||
* not yet set) then return pa == va to avoid infinite recursion. | * not yet set) then return pa == va to avoid infinite recursion. | ||||
*/ | */ | ||||
if (PTD == 0) { | if (PTD == 0) { | ||||
s = _kvm_pa2off(kd, va, pa); | s = _kvm_pa2off(kd, va, pa); | ||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, | _kvm_err(kd, kd->program, | ||||
"_kvm_vatop_pae: bootstrap data not in dump"); | "_i386_vatop_pae: bootstrap data not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} else | } else | ||||
return (PAGE_SIZE - offset); | return (I386_PAGE_SIZE - offset); | ||||
} | } | ||||
pdeindex = va >> PDRSHIFT_PAE; | pdeindex = va >> I386_PDRSHIFT_PAE; | ||||
pde = PTD[pdeindex]; | pde = le64toh(PTD[pdeindex]); | ||||
if (((u_long)pde & PG_V) == 0) { | if ((pde & I386_PG_V) == 0) { | ||||
_kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid"); | _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
if ((u_long)pde & PG_PS) { | if (pde & I386_PG_PS) { | ||||
/* | /* | ||||
* No second-level page table; ptd describes one 2MB page. | * No second-level page table; ptd describes one 2MB | ||||
* (We assume that the kernel wouldn't set PG_PS without enabling | * page. (We assume that the kernel wouldn't set | ||||
* it cr0). | * PG_PS without enabling it cr0). | ||||
*/ | */ | ||||
#define PAGE2M_MASK (NBPDR_PAE - 1) | offset = va & I386_PAGE_PS_MASK_PAE; | ||||
#define PG_FRAME2M (~PAGE2M_MASK) | a = (pde & I386_PG_PS_FRAME_PAE) + offset; | ||||
pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK); | s = _kvm_pa2off(kd, a, pa); | ||||
s = _kvm_pa2off(kd, pde_pa, &ofs); | |||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, | _kvm_err(kd, kd->program, | ||||
"_kvm_vatop: 2MB page address not in dump"); | "_i386_vatop: 2MB page address not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
*pa = ofs; | return (I386_NBPDR_PAE - offset); | ||||
return (NBPDR_PAE - (va & PAGE2M_MASK)); | |||||
} | } | ||||
pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1); | pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG_PAE - 1); | ||||
pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde)); | pte_pa = (pde & I386_PG_FRAME_PAE) + (pteindex * sizeof(pde)); | ||||
s = _kvm_pa2off(kd, pte_pa, &ofs); | s = _kvm_pa2off(kd, pte_pa, &ofs); | ||||
if (s < sizeof pte) { | if (s < sizeof(pte)) { | ||||
_kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found"); | _kvm_err(kd, kd->program, "_i386_vatop_pae: pdpe_pa not found"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
/* XXX This has to be a physical address read, kvm_read is virtual */ | /* XXX This has to be a physical address read, kvm_read is virtual */ | ||||
if (lseek(kd->pmfd, ofs, 0) == -1) { | if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { | ||||
_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek"); | _kvm_syserr(kd, kd->program, "_i386_vatop_pae: read"); | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { | pte = le64toh(pte); | ||||
_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read"); | if ((pte & I386_PG_V) == 0) { | ||||
_kvm_err(kd, kd->program, "_i386_vatop_pae: pte not valid"); | |||||
goto invalid; | goto invalid; | ||||
} | } | ||||
if (((uint64_t)pte & PG_V) == 0) { | |||||
_kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid"); | |||||
goto invalid; | |||||
} | |||||
a = ((uint64_t)pte & PG_FRAME_PAE) + offset; | a = (pte & I386_PG_FRAME_PAE) + offset; | ||||
s =_kvm_pa2off(kd, a, pa); | s = _kvm_pa2off(kd, a, pa); | ||||
if (s == 0) { | if (s == 0) { | ||||
_kvm_err(kd, kd->program, | _kvm_err(kd, kd->program, | ||||
"_kvm_vatop_pae: address not in dump"); | "_i386_vatop_pae: address not in dump"); | ||||
goto invalid; | goto invalid; | ||||
} else | } else | ||||
return (PAGE_SIZE - offset); | return (I386_PAGE_SIZE - offset); | ||||
invalid: | invalid: | ||||
_kvm_err(kd, 0, "invalid address (0x%lx)", va); | _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | static int | ||||
_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) | _i386_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) | ||||
{ | { | ||||
if (kd->vmst->minidump) | |||||
return (_kvm_minidump_kvatop(kd, va, pa)); | |||||
if (ISALIVE(kd)) { | if (ISALIVE(kd)) { | ||||
_kvm_err(kd, 0, "vatop called in live kernel!"); | _kvm_err(kd, 0, "vatop called in live kernel!"); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (kd->vmst->pae) | if (kd->vmst->pae) | ||||
return (_kvm_vatop_pae(kd, va, pa)); | return (_i386_vatop_pae(kd, va, pa)); | ||||
else | else | ||||
return (_kvm_vatop(kd, va, pa)); | return (_i386_vatop(kd, va, pa)); | ||||
} | } | ||||
int | |||||
_i386_native(kvm_t *kd) | |||||
{ | |||||
#ifdef __i386__ | |||||
return (1); | |||||
#else | |||||
return (0); | |||||
#endif | |||||
} | |||||
struct kvm_arch kvm_i386 = { | |||||
.ka_probe = _i386_probe, | |||||
.ka_initvtop = _i386_initvtop, | |||||
.ka_freevtop = _i386_freevtop, | |||||
.ka_kvatop = _i386_kvatop, | |||||
.ka_native = _i386_native, | |||||
}; | |||||
KVM_ARCH(kvm_i386); |