diff options
Diffstat (limited to 'lib/libkvm/kvm_sparc64.c')
-rw-r--r-- | lib/libkvm/kvm_sparc64.c | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/lib/libkvm/kvm_sparc64.c b/lib/libkvm/kvm_sparc64.c index 435eb43..081ddf8 100644 --- a/lib/libkvm/kvm_sparc64.c +++ b/lib/libkvm/kvm_sparc64.c @@ -62,6 +62,7 @@ static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; #include <vm/vm.h> #include <vm/vm_param.h> +#include <machine/kerneldump.h> #include <machine/tte.h> #include <machine/tsb.h> @@ -75,23 +76,78 @@ static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; #endif struct vmstate { - vm_offset_t vm_tsb; + off_t vm_tsb_off; vm_size_t vm_tsb_mask; + int vm_nregions; + struct sparc64_dump_reg *vm_regions; }; void _kvm_freevtop(kvm_t *kd) { if (kd->vmst != 0) { + free(kd->vmst->vm_regions); free(kd->vmst); } } +static int +_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size) +{ + + /* XXX This has to be a raw file read, kvm_read is virtual. */ + if (lseek(kd->pmfd, pos, SEEK_SET) == -1) { + _kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek"); + return (0); + } + if (read(kd->pmfd, buf, size) != size) { + _kvm_syserr(kd, kd->program, "_kvm_read_phys: read"); + return (0); + } + return (1); +} + +static int +_kvm_reg_cmp(const void *a, const void *b) +{ + const struct sparc64_dump_reg *ra, *rb; + + ra = a; + rb = b; + if (ra->dr_pa < rb->dr_pa) + return (-1); + else if (ra->dr_pa >= rb->dr_pa + rb->dr_size) + return (1); + else + return (0); +} + +#define KVM_OFF_NOTFOUND 0 + +static off_t +_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size) +{ + struct sparc64_dump_reg *reg, key; + vm_offset_t o; + + key.dr_pa = pa; + reg = bsearch(&key, vm->vm_regions, vm->vm_nregions, + sizeof(*vm->vm_regions), _kvm_reg_cmp); + if (reg == NULL) + return (KVM_OFF_NOTFOUND); + o = pa - reg->dr_pa; + if (o + size > reg->dr_size) + return (KVM_OFF_NOTFOUND); + return (reg->dr_offs + o); +} + int _kvm_initvtop(kvm_t *kd) { - struct nlist nlist[2]; + struct sparc64_dump_hdr hdr; + struct sparc64_dump_reg *regs; struct vmstate *vm; + size_t regsz; vm_offset_t pa; vm_size_t mask; @@ -101,25 +157,36 @@ _kvm_initvtop(kvm_t *kd) return (-1); } kd->vmst = vm; - vm->vm_tsb = 0; - nlist[0].n_name = "tsb_kernel_phys"; - nlist[1].n_name = "tsb_kernel_mask"; - nlist[2].n_name = 0; + if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr))) + goto fail_vm; + pa = hdr.dh_tsb_pa; - if (kvm_nlist(kd, nlist) != 0) { - _kvm_err(kd, kd->program, "bad namelist"); - return (-1); + regsz = hdr.dh_nregions * sizeof(*regs); + regs = _kvm_malloc(kd, regsz); + if (regs == NULL) { + _kvm_err(kd, kd->program, "cannot allocate regions"); + goto fail_vm; } - if (kvm_read(kd, nlist[0].n_value, &pa, sizeof(pa)) != sizeof(pa) || - kvm_read(kd, nlist[1].n_value, &mask, sizeof(mask)) != - sizeof(mask)) { - _kvm_err(kd, kd->program, "cannot read tsb_kernel_phys"); - return (-1); + if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz)) + goto fail_regs; + qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp); + + vm->vm_tsb_mask = hdr.dh_tsb_mask; + vm->vm_regions = regs; + vm->vm_nregions = hdr.dh_nregions; + vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size); + if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) { + _kvm_err(kd, kd->program, "tsb not found in dump"); + goto fail_regs; } - vm->vm_tsb = pa; - vm->vm_tsb_mask = mask; return (0); + +fail_regs: + free(regs); +fail_vm: + free(vm); + return (-1); } int @@ -127,29 +194,25 @@ _kvm_kvatop(kvm_t *kd, u_long va, u_long *pa) { struct vmstate *vm; struct tte tte; - u_long offset; - u_long tte_pa; - u_long vpn; + off_t tte_off, pa_off; + u_long pg_off, vpn; + int rest; vpn = btop(va); - offset = va & PAGE_MASK; - tte_pa = kd->vmst->vm_tsb + + pg_off = va & PAGE_MASK; + tte_off = kd->vmst->vm_tsb_off + ((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT); - /* XXX This has to be a physical address read, kvm_read is virtual */ - if (lseek(kd->pmfd, tte_pa, 0) == -1) { - _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek"); + if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte))) goto invalid; - } - if (read(kd->pmfd, &tte, sizeof(tte)) != sizeof(tte)) { - _kvm_syserr(kd, kd->program, "_kvm_vatop: read"); - goto invalid; - } if (!tte_match(&tte, va)) goto invalid; - - *pa = TTE_GET_PA(&tte) + offset; - return (PAGE_SIZE - offset); + rest = PAGE_SIZE - pg_off; + pa_off = _kvm_find_off(kd->vmst, TTE_GET_PA(&tte), rest); + if (pa_off == KVM_OFF_NOTFOUND) + goto invalid; + *pa = pa_off + pg_off; + return (rest); invalid: _kvm_err(kd, 0, "invalid address (%x)", va); |