1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-20 02:38:43 +00:00

Add support for PBVM addresses. In a nutshell this means:

o   get the physical address and size of the PBVM page table. This
    can be found in the bootinfo structure, of which the physical
    address is recorded as the ELF entry point.
o   translate region 4 virtual addresses to physical addresses using
    the PBVM page table.

In _kvm_kvatop() make the distinction between physical address and
core file offset a little clearer to avoid confusion. To further
enhance readability, always store the translated address into pa
so that it's obvious how the translation from va to pa happened.

Approved by:	re (blanket)
This commit is contained in:
Marcel Moolenaar 2011-08-06 15:59:54 +00:00
parent c2aedca43b
commit d69bc9bcbe
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224680

View File

@ -33,6 +33,7 @@
#include <sys/mman.h>
#include <machine/atomic.h>
#include <machine/bootinfo.h>
#include <machine/pte.h>
#include <kvm.h>
@ -51,11 +52,16 @@
#define KPTE_DIR0_INDEX(va,ps) ((((va)/(ps)) / NKPTEPG(ps)) / NKPTEDIR(ps))
#define KPTE_DIR1_INDEX(va,ps) ((((va)/(ps)) / NKPTEPG(ps)) % NKPTEDIR(ps))
#define PBVM_BASE 0x9ffc000000000000UL
#define PBVM_PGSZ (64 * 1024)
struct vmstate {
void *mmapbase;
size_t mmapsize;
size_t pagesize;
u_long kptdir;
u_long *pbvm_pgtbl;
u_int pbvm_pgtblsz;
};
/*
@ -110,11 +116,28 @@ _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs, size_t pgsz)
return (pgsz - ((size_t)pa & (pgsz - 1)));
}
static ssize_t
_kvm_read_phys(kvm_t *kd, uint64_t pa, void *buf, size_t bufsz)
{
off_t ofs;
size_t sz;
sz = _kvm_pa2off(kd, pa, &ofs, 0);
if (sz < bufsz)
return ((ssize_t)sz);
if (lseek(kd->pmfd, ofs, 0) == -1)
return (-1);
return (read(kd->pmfd, buf, bufsz));
}
void
_kvm_freevtop(kvm_t *kd)
{
struct vmstate *vm = kd->vmst;
if (vm->pbvm_pgtbl != NULL)
free(vm->pbvm_pgtbl);
if (vm->mmapbase != NULL)
munmap(vm->mmapbase, vm->mmapsize);
free(vm);
@ -124,10 +147,12 @@ _kvm_freevtop(kvm_t *kd)
int
_kvm_initvtop(kvm_t *kd)
{
struct bootinfo bi;
struct nlist nl[2];
uint64_t va;
Elf64_Ehdr *ehdr;
size_t hdrsz;
ssize_t sz;
kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
if (kd->vmst == NULL) {
@ -145,6 +170,42 @@ _kvm_initvtop(kvm_t *kd)
if (_kvm_maphdrs(kd, hdrsz) == -1)
return (-1);
/*
* Load the PBVM page table. We need this to resolve PBVM addresses.
* The PBVM page table is obtained from the bootinfo structure, of
* which the physical address is given to us in e_entry. If e_entry
* is 0, then this is assumed to be a pre-PBVM kernel.
*/
if (ehdr->e_entry != 0) {
sz = _kvm_read_phys(kd, ehdr->e_entry, &bi, sizeof(bi));
if (sz != sizeof(bi)) {
_kvm_err(kd, kd->program,
"cannot read bootinfo from PA %#lx", ehdr->e_entry);
return (-1);
}
if (bi.bi_magic != BOOTINFO_MAGIC) {
_kvm_err(kd, kd->program, "invalid bootinfo");
return (-1);
}
kd->vmst->pbvm_pgtbl = _kvm_malloc(kd, bi.bi_pbvm_pgtblsz);
if (kd->vmst->pbvm_pgtbl == NULL) {
_kvm_err(kd, kd->program, "cannot allocate page table");
return (-1);
}
kd->vmst->pbvm_pgtblsz = bi.bi_pbvm_pgtblsz;
sz = _kvm_read_phys(kd, bi.bi_pbvm_pgtbl, kd->vmst->pbvm_pgtbl,
bi.bi_pbvm_pgtblsz);
if (sz != bi.bi_pbvm_pgtblsz) {
_kvm_err(kd, kd->program,
"cannot read page table from PA %#lx",
bi.bi_pbvm_pgtbl);
return (-1);
}
} else {
kd->vmst->pbvm_pgtbl = NULL;
kd->vmst->pbvm_pgtblsz = 0;
}
/*
* At this point we've got enough information to use kvm_read() for
* direct mapped (ie region 6 and region 7) address, such as symbol
@ -174,17 +235,18 @@ _kvm_initvtop(kvm_t *kd)
}
int
_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
_kvm_kvatop(kvm_t *kd, u_long va, off_t *ofs)
{
struct ia64_lpte pte;
uint64_t pgaddr, pt0addr, pt1addr;
uint64_t pa, pgaddr, pt0addr, pt1addr;
size_t pgno, pgsz, pt0no, pt1no;
if (va >= REGION_BASE(6)) {
/* Regions 6 and 7: direct mapped. */
return (_kvm_pa2off(kd, REGION_ADDR(va), pa, 0));
pa = REGION_ADDR(va);
return (_kvm_pa2off(kd, pa, ofs, 0));
} else if (va >= REGION_BASE(5)) {
/* Region 5: virtual. */
/* Region 5: Kernel Virtual Memory. */
va = REGION_ADDR(va);
pgsz = kd->vmst->pagesize;
pt0no = KPTE_DIR0_INDEX(va, pgsz);
@ -207,12 +269,24 @@ _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
goto fail;
if (!(pte.pte & PTE_PRESENT))
goto fail;
va = (pte.pte & PTE_PPN_MASK) + (va & (pgsz - 1));
return (_kvm_pa2off(kd, va, pa, pgsz));
pa = (pte.pte & PTE_PPN_MASK) + (va & (pgsz - 1));
return (_kvm_pa2off(kd, pa, ofs, pgsz));
} else if (va >= PBVM_BASE) {
/* Region 4: Pre-Boot Virtual Memory (PBVM). */
va -= PBVM_BASE;
pgsz = PBVM_PGSZ;
pt0no = va / pgsz;
if (pt0no >= (kd->vmst->pbvm_pgtblsz >> 3))
goto fail;
pt0addr = kd->vmst->pbvm_pgtbl[pt0no];
if (!(pt0addr & PTE_PRESENT))
goto fail;
pa = (pt0addr & PTE_PPN_MASK) + va % pgsz;
return (_kvm_pa2off(kd, pa, ofs, pgsz));
}
fail:
_kvm_err(kd, kd->program, "invalid kernel virtual address");
*pa = ~0UL;
*ofs = ~0UL;
return (0);
}