Page MenuHomeFreeBSD

D15583.id44442.diff
No OneTemporary

D15583.id44442.diff

Index: lib/libkvm/kvm_minidump_mips.c
===================================================================
--- lib/libkvm/kvm_minidump_mips.c
+++ lib/libkvm/kvm_minidump_mips.c
@@ -45,6 +45,8 @@
#include <string.h>
#include <unistd.h>
+#include "../../sys/mips/include/cca.h"
+#define _KVM_MINIDUMP
#include "../../sys/mips/include/cpuregs.h"
#include "../../sys/mips/include/minidump.h"
Index: share/man/man4/pci.4
===================================================================
--- share/man/man4/pci.4
+++ share/man/man4/pci.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 20, 2017
+.Dd June 14, 2018
.Dt PCI 4
.Os
.Sh NAME
@@ -333,6 +333,72 @@
reading registers, above, also apply to writing
.Tn PCI
configuration registers.
+.It PCIOCBARMMAP
+This
+.Xr ioctl 2
+command allows userspace processes to
+.Xr mmap 2
+the memory-mapped PCI BAR into its address space.
+The input parameters and results are passed in the
+.Va pci_bar_mmap
+structure, which has the following fields:
+.Bl -tag -width Vt struct pcise pbm_sel
+.It Vt uint64_t pbm_map_base
+Reports the established mapping base to the caller.
+If
+.Va PCIIO_BAR_MMAP_FIXED
+flag was specified, then this field must be filled before the call
+with the desired address for the mapping.
+.It Vt uint64_t pbm_map_length
+Reports the mapped length of the BAR, in bytes.
+Its .Vt uint64_t value is always multiple of machine pages.
+.It Vt int64_t pbm_bar_length
+Reports length of the bar as exposed by the device.
+.It Vt int pbm_bar_off
+Reports offset from the mapped base to the start of the
+first register in the bar.
+.It Vt struct pcisel pbm_sel
+Should be filled before the call.
+Describes the device to operate on.
+.It Vt int pbm_reg
+The BAR index to mmap.
+.It Vt int pbm_flags
+Flags which augments the operation.
+See below.
+.It Vt int pbm_memattr
+The caching attribute for the mapping.
+Typical values are
+.Dv VM_MEMATTR_UNCACHEABLE
+for control registers BARs, and
+.Dv VM_MEMATTR_WRITE_COMBINING
+for frame buffers.
+Regular memory-like BAR should be mapped with
+.Dv VM_MEMATTR_DEFAULT
+attribute.
+.El
+.Pp
+Currently defined flags are:
+.Bl -tag -width PCIIO_BAR_MMAP_ACTIVATE
+.It PCIIO_BAR_MMAP_FIXED
+The resulted mappings should be established at the address
+specified by the
+.Va pbm_map_base
+member, otherwise fail.
+.It PCIIO_BAR_MMAP_EXCL
+Must be used together with
+.Vd PCIIO_BAR_MMAP_FIXED
+If the specified base contains already established mappings, the
+operation fails instead of implicitly unmapping them.
+.It PCIIO_BAR_MMAP_RW
+The requested mapping allows both reading and writing.
+Without the flag, read-only mapping is established.
+Note that it is common for the device registers to have side-effects
+even on reads.
+.It PCIIO_BAR_MMAP_ACTIVATE
+(Unimplemented) If the BAR is not activated, activate it in the course
+of mapping.
+Currently attempt to mmap an inactive BAR results in error.
+.El
.El
.Sh LOADER TUNABLES
Tunables can be set at the
Index: sys/amd64/amd64/pmap.c
===================================================================
--- sys/amd64/amd64/pmap.c
+++ sys/amd64/amd64/pmap.c
@@ -1468,6 +1468,14 @@
return (entry);
}
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode >= 0 && mode < PAT_INDEX_SIZE &&
+ pat_index[(int)mode] >= 0);
+}
+
/*
* Determine the appropriate bits to set in a PTE or PDE for a specified
* caching mode.
@@ -1477,7 +1485,7 @@
{
int cache_bits, pat_flag, pat_idx;
- if (mode < 0 || mode >= PAT_INDEX_SIZE || pat_index[mode] < 0)
+ if (!pmap_is_valid_memattr(pmap, mode))
panic("Unknown caching mode %d\n", mode);
switch (pmap->pm_type) {
Index: sys/arm/arm/pmap-v4.c
===================================================================
--- sys/arm/arm/pmap-v4.c
+++ sys/arm/arm/pmap-v4.c
@@ -4859,4 +4859,9 @@
panic("Can't change memattr on page with existing mappings");
}
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+ return (mode == VM_MEMATTR_DEFAULT || mode == VM_MEMATTR_UNCACHEABLE);
+}
Index: sys/arm/arm/pmap-v6.c
===================================================================
--- sys/arm/arm/pmap-v6.c
+++ sys/arm/arm/pmap-v6.c
@@ -393,12 +393,21 @@
CTASSERT(VM_MEMATTR_DEVICE == 2);
CTASSERT(VM_MEMATTR_SO == 3);
CTASSERT(VM_MEMATTR_WRITE_THROUGH == 4);
+#define VM_MEMATTR_END (VM_MEMATTR_WRITE_THROUGH + 1)
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode >= 0 && mode < VM_MEMATTR_END);
+}
static inline uint32_t
vm_memattr_to_pte2(vm_memattr_t ma)
{
- KASSERT((u_int)ma < 5, ("%s: bad vm_memattr_t %d", __func__, ma));
+ KASSERT((u_int)ma < VM_MEMATTR_END,
+ ("%s: bad vm_memattr_t %d", __func__, ma));
return (pte2_attr_tab[(u_int)ma]);
}
Index: sys/arm64/arm64/pmap.c
===================================================================
--- sys/arm64/arm64/pmap.c
+++ sys/arm64/arm64/pmap.c
@@ -5102,3 +5102,10 @@
}
}
}
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode >= VM_MEMATTR_DEVICE && mode <= VM_MEMATTR_WRITE_THROUGH);
+}
Index: sys/compat/freebsd32/freebsd32_ioctl.h
===================================================================
--- sys/compat/freebsd32/freebsd32_ioctl.h
+++ sys/compat/freebsd32/freebsd32_ioctl.h
@@ -95,11 +95,23 @@
u_int32_t status; /* request status */
};
+struct pci_bar_mmap32 {
+ uint32_t pbm_map_base;
+ uint32_t pbm_map_length;
+ uint32_t pbm_bar_length1, pbm_bar_length2;
+ int pbm_bar_off;
+ struct pcisel pbm_sel;
+ int pbm_reg;
+ int pbm_flags;
+ int pbm_memattr;
+};
+
#define CDIOREADTOCENTRYS_32 _IOWR('c', 5, struct ioc_read_toc_entry32)
#define FIODGNAME_32 _IOW('f', 120, struct fiodgname_arg32)
#define MEMRANGE_GET32 _IOWR('m', 50, struct mem_range_op32)
#define MEMRANGE_SET32 _IOW('m', 51, struct mem_range_op32)
#define PCIOCGETCONF_32 _IOWR('p', 5, struct pci_conf_io32)
#define SG_IO_32 _IOWR(SGIOC, 0x85, struct sg_io_hdr32)
+#define PCIOCBARMMAP_32 _IOWR('p', 8, struct pci_bar_mmap32)
#endif /* _COMPAT_FREEBSD32_IOCTL_H_ */
Index: sys/compat/freebsd32/freebsd32_ioctl.c
===================================================================
--- sys/compat/freebsd32/freebsd32_ioctl.c
+++ sys/compat/freebsd32/freebsd32_ioctl.c
@@ -53,6 +53,7 @@
#include <compat/freebsd32/freebsd32.h>
#include <compat/freebsd32/freebsd32_ioctl.h>
+#include <compat/freebsd32/freebsd32_misc.h>
#include <compat/freebsd32/freebsd32_proto.h>
CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8);
@@ -248,6 +249,40 @@
return (error);
}
+static int
+freebsd32_ioctl_barmmap(struct thread *td,
+ struct freebsd32_ioctl_args *uap, struct file *fp)
+{
+ struct pci_bar_mmap32 pbm32;
+ struct pci_bar_mmap pbm;
+ int error;
+
+ error = copyin(uap->data, &pbm32, sizeof(pbm32));
+ if (error != 0)
+ return (error);
+ PTRIN_CP(pbm32, pbm, pbm_map_base);
+ CP(pbm32, pbm, pbm_sel);
+ CP(pbm32, pbm, pbm_reg);
+ CP(pbm32, pbm, pbm_flags);
+ CP(pbm32, pbm, pbm_memattr);
+ pbm.pbm_bar_length = PAIR32TO64(uint64_t, pbm32.pbm_bar_length);
+ error = fo_ioctl(fp, PCIOCBARMMAP, (caddr_t)&pbm, td->td_ucred, td);
+ if (error == 0) {
+ PTROUT_CP(pbm, pbm32, pbm_map_base);
+ CP(pbm, pbm32, pbm_map_length);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ pbm32.pbm_bar_length1 = pbm.pbm_bar_length;
+ pbm32.pbm_bar_length2 = pbm.pbm_bar_length >> 32;
+#else
+ pbm32.pbm_bar_length1 = pbm.pbm_bar_length >> 32;
+ pbm32.pbm_bar_length2 = pbm.pbm_bar_length;
+#endif
+ CP(pbm, pbm32, pbm_bar_off);
+ error = copyout(&pbm32, uap->data, sizeof(pbm32));
+ }
+ return (error);
+}
+
static int
freebsd32_ioctl_sg(struct thread *td,
struct freebsd32_ioctl_args *uap, struct file *fp)
@@ -355,6 +390,10 @@
error = freebsd32_ioctl_sg(td, uap, fp);
break;
+ case PCIOCBARMMAP_32:
+ error = freebsd32_ioctl_barmmap(td, uap, fp);
+ break;
+
default:
fdrop(fp, td);
ap.fd = uap->fd;
@@ -364,5 +403,5 @@
}
fdrop(fp, td);
- return error;
+ return (error);
}
Index: sys/dev/pci/pci_user.c
===================================================================
--- sys/dev/pci/pci_user.c
+++ sys/dev/pci/pci_user.c
@@ -31,6 +31,7 @@
#include "opt_bus.h" /* XXX trim includes */
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -39,13 +40,19 @@
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/queue.h>
-#include <sys/types.h>
+#include <sys/rwlock.h>
+#include <sys/sglist.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
#include <sys/bus.h>
#include <machine/bus.h>
@@ -696,6 +703,77 @@
}
}
+static int
+pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
+{
+ vm_map_t map;
+ vm_object_t obj;
+ struct thread *td;
+ struct sglist *sg;
+ struct pci_map *pm;
+ vm_paddr_t pbase;
+ vm_size_t plen;
+ vm_offset_t addr;
+ vm_prot_t prot;
+ int error, flags;
+
+ td = curthread;
+ map = &td->td_proc->p_vmspace->vm_map;
+ if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
+ PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
+ pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
+ !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
+ return (EINVAL);
+
+ /* Fetch the BAR physical base and length. */
+ pm = pci_find_bar(pcidev, pbm->pbm_reg);
+ if (pm == NULL)
+ return (EINVAL);
+ if (!pci_bar_enabled(pcidev, pm))
+ return (EBUSY); /* XXXKIB enable if _ACTIVATE */
+ if (!PCI_BAR_MEM(pm->pm_value))
+ return (EIO);
+ pbase = trunc_page(pm->pm_value);
+ plen = round_page(pm->pm_value + ((pci_addr_t)1 << pm->pm_size)) -
+ pbase;
+ prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
+ VM_PROT_WRITE : 0);
+
+ /* Create vm structures and mmap. */
+ sg = sglist_alloc(1, M_WAITOK);
+ error = sglist_append_phys(sg, pbase, plen);
+ if (error != 0)
+ goto out;
+ obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
+ if (obj == NULL) {
+ error = EIO;
+ goto out;
+ }
+ obj->memattr = pbm->pbm_memattr;
+ flags = MAP_SHARED;
+ addr = 0;
+ if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
+ addr = (uintptr_t)pbm->pbm_map_base;
+ flags |= MAP_FIXED;
+ }
+ if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
+ flags |= MAP_CHECK_EXCL;
+ error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
+ FALSE, td);
+ if (error != 0) {
+ vm_object_deallocate(obj);
+ goto out;
+ }
+ pbm->pbm_map_base = (void *)addr;
+ pbm->pbm_map_length = plen;
+ pbm->pbm_bar_off = pm->pm_value - pbase;
+ pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
+
+out:
+ sglist_free(sg);
+ return (error);
+}
+
static int
pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
{
@@ -709,6 +787,7 @@
struct pci_list_vpd_io *lvio;
struct pci_match_conf *pattern_buf;
struct pci_map *pm;
+ struct pci_bar_mmap *pbm;
size_t confsz, iolen;
int error, ionum, i, num_patterns;
union pci_conf_union pcu;
@@ -730,6 +809,7 @@
#endif
case PCIOCGETBAR:
case PCIOCLISTVPD:
+ case PCIOCBARMMAP:
break;
default:
return (EPERM);
@@ -1053,6 +1133,18 @@
}
error = pci_list_vpd(pcidev, lvio);
break;
+
+ case PCIOCBARMMAP:
+ pbm = (struct pci_bar_mmap *)data;
+ if ((flag & FWRITE) == 0 &&
+ (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0)
+ return (EPERM);
+ pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
+ pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
+ pbm->pbm_sel.pc_func);
+ error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
+ break;
+
default:
error = ENOTTY;
break;
Index: sys/i386/i386/copyout.c
===================================================================
--- sys/i386/i386/copyout.c
+++ sys/i386/i386/copyout.c
@@ -130,7 +130,8 @@
}
for (i = 0, pte = vtopte(kaddr); i < plen; i++, pte++) {
*pte = PG_V | PG_RW | PG_A | PG_M | VM_PAGE_TO_PHYS(m[i]) |
- pmap_cache_bits(pmap_page_get_memattr(m[i]), FALSE);
+ pmap_cache_bits(kernel_pmap, pmap_page_get_memattr(m[i]),
+ FALSE);
invlpg(kaddr + ptoa(i));
}
kaddr += uva - trunc_page(uva);
Index: sys/i386/i386/pmap.c
===================================================================
--- sys/i386/i386/pmap.c
+++ sys/i386/i386/pmap.c
@@ -1039,16 +1039,24 @@
* Low level helper routines.....
***************************************************/
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode >= 0 && mode < PAT_INDEX_SIZE &&
+ pat_index[(int)mode] >= 0);
+}
+
/*
* Determine the appropriate bits to set in a PTE or PDE for a specified
* caching mode.
*/
int
-pmap_cache_bits(int mode, boolean_t is_pde)
+pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde)
{
int cache_bits, pat_flag, pat_idx;
- if (mode < 0 || mode >= PAT_INDEX_SIZE || pat_index[mode] < 0)
+ if (!pmap_is_valid_memattr(pmap, mode))
panic("Unknown caching mode %d\n", mode);
/* The PAT bit is different for PTE's and PDE's. */
@@ -1718,7 +1726,8 @@
pt_entry_t *pte;
pte = vtopte(va);
- pte_store(pte, pa | PG_RW | PG_V | pmap_cache_bits(mode, 0));
+ pte_store(pte, pa | PG_RW | PG_V | pmap_cache_bits(kernel_pmap,
+ mode, 0));
}
/*
@@ -1813,7 +1822,8 @@
endpte = pte + count;
while (pte < endpte) {
m = *ma++;
- pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 0);
+ pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(kernel_pmap,
+ m->md.pat_mode, 0);
if ((*pte & (PG_FRAME | PG_PTE_CACHE)) != pa) {
oldpte |= *pte;
#if defined(PAE) || defined(PAE_TABLES)
@@ -3716,7 +3726,8 @@
/*
* Now validate mapping with desired protection/wiring.
*/
- newpte = (pt_entry_t)(pa | pmap_cache_bits(m->md.pat_mode, 0) | PG_V);
+ newpte = (pt_entry_t)(pa | pmap_cache_bits(pmap, m->md.pat_mode, 0) |
+ PG_V);
if ((prot & VM_PROT_WRITE) != 0) {
newpte |= PG_RW;
if ((newpte & PG_MANAGED) != 0)
@@ -3806,7 +3817,7 @@
" in pmap %p", va, pmap);
return (FALSE);
}
- newpde = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 1) |
+ newpde = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(pmap, m->md.pat_mode, 1) |
PG_PS | PG_V;
if ((m->oflags & VPO_UNMANAGED) == 0) {
newpde |= PG_MANAGED;
@@ -3994,7 +4005,7 @@
*/
pmap->pm_stats.resident_count++;
- pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 0);
+ pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(pmap, m->md.pat_mode, 0);
#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
pa |= pg_nx;
@@ -4082,8 +4093,8 @@
* "pa" will not affect the termination of this loop.
*/
PMAP_LOCK(pmap);
- for (pa = ptepa | pmap_cache_bits(pat_mode, 1); pa < ptepa +
- size; pa += NBPDR) {
+ for (pa = ptepa | pmap_cache_bits(pmap, pat_mode, 1);
+ pa < ptepa + size; pa += NBPDR) {
pde = pmap_pde(pmap, addr);
if (*pde == 0) {
pde_store(pde, pa | PG_PS | PG_M | PG_A |
@@ -4348,7 +4359,7 @@
if (*cmap_pte2)
panic("pmap_zero_page: CMAP2 busy");
*cmap_pte2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(m) | PG_A | PG_M |
- pmap_cache_bits(m->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, m->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr2);
pagezero(pc->pc_cmap_addr2);
*cmap_pte2 = 0;
@@ -4379,7 +4390,7 @@
if (*cmap_pte2)
panic("pmap_zero_page_area: CMAP2 busy");
*cmap_pte2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(m) | PG_A | PG_M |
- pmap_cache_bits(m->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, m->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr2);
if (off == 0 && size == PAGE_SIZE)
pagezero(pc->pc_cmap_addr2);
@@ -4409,10 +4420,10 @@
if (*cmap_pte2)
panic("pmap_copy_page: CMAP2 busy");
*cmap_pte1 = PG_V | VM_PAGE_TO_PHYS(src) | PG_A |
- pmap_cache_bits(src->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, src->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr1);
*cmap_pte2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(dst) | PG_A | PG_M |
- pmap_cache_bits(dst->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, dst->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr2);
bcopy(pc->pc_cmap_addr1, pc->pc_cmap_addr2, PAGE_SIZE);
*cmap_pte1 = 0;
@@ -4451,10 +4462,10 @@
b_pg_offset = b_offset & PAGE_MASK;
cnt = min(cnt, PAGE_SIZE - b_pg_offset);
*cmap_pte1 = PG_V | VM_PAGE_TO_PHYS(a_pg) | PG_A |
- pmap_cache_bits(a_pg->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, a_pg->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr1);
*cmap_pte2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(b_pg) | PG_A |
- PG_M | pmap_cache_bits(b_pg->md.pat_mode, 0);
+ PG_M | pmap_cache_bits(kernel_pmap, b_pg->md.pat_mode, 0);
invlcaddr(pc->pc_cmap_addr2);
a_cp = pc->pc_cmap_addr1 + a_pg_offset;
b_cp = pc->pc_cmap_addr2 + b_pg_offset;
@@ -5426,7 +5437,8 @@
if (*cmap_pte2)
panic("pmap_flush_page: CMAP2 busy");
*cmap_pte2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(m) |
- PG_A | PG_M | pmap_cache_bits(m->md.pat_mode, 0);
+ PG_A | PG_M | pmap_cache_bits(kernel_pmap, m->md.pat_mode,
+ 0);
invlcaddr(pc->pc_cmap_addr2);
sva = (vm_offset_t)pc->pc_cmap_addr2;
eva = sva + PAGE_SIZE;
@@ -5487,8 +5499,8 @@
if (base < VM_MIN_KERNEL_ADDRESS)
return (EINVAL);
- cache_bits_pde = pmap_cache_bits(mode, 1);
- cache_bits_pte = pmap_cache_bits(mode, 0);
+ cache_bits_pde = pmap_cache_bits(kernel_pmap, mode, 1);
+ cache_bits_pte = pmap_cache_bits(kernel_pmap, mode, 0);
changed = FALSE;
/*
@@ -5694,7 +5706,7 @@
KASSERT(*pte == 0, ("pmap_quick_enter_page: PTE busy"));
*pte = PG_V | PG_RW | VM_PAGE_TO_PHYS(m) | PG_A | PG_M |
- pmap_cache_bits(pmap_page_get_memattr(m), 0);
+ pmap_cache_bits(kernel_pmap, pmap_page_get_memattr(m), 0);
invlpg(qaddr);
return (qaddr);
@@ -5745,7 +5757,7 @@
VM_ALLOC_NORMAL | VM_ALLOC_WIRED | VM_ALLOC_WAITOK);
pte_store(&trm_pte[atop(af - prev_addr)], VM_PAGE_TO_PHYS(m) |
PG_M | PG_A | PG_RW | PG_V | pgeflag |
- pmap_cache_bits(VM_MEMATTR_DEFAULT, FALSE));
+ pmap_cache_bits(kernel_pmap, VM_MEMATTR_DEFAULT, FALSE));
}
*addrp = prev_addr;
return (0);
@@ -5766,7 +5778,7 @@
if ((pd_m->flags & PG_ZERO) == 0)
pmap_zero_page(pd_m);
PTD[TRPTDI] = VM_PAGE_TO_PHYS(pd_m) | PG_M | PG_A | PG_RW | PG_V |
- pmap_cache_bits(VM_MEMATTR_DEFAULT, TRUE);
+ pmap_cache_bits(kernel_pmap, VM_MEMATTR_DEFAULT, TRUE);
}
void *
Index: sys/i386/i386/vm_machdep.c
===================================================================
--- sys/i386/i386/vm_machdep.c
+++ sys/i386/i386/vm_machdep.c
@@ -584,7 +584,7 @@
ptep = vtopte(sf->kva);
opte = *ptep;
*ptep = VM_PAGE_TO_PHYS(sf->m) | PG_RW | PG_V |
- pmap_cache_bits(sf->m->md.pat_mode, 0);
+ pmap_cache_bits(kernel_pmap, sf->m->md.pat_mode, 0);
/*
* Avoid unnecessary TLB invalidations: If the sf_buf's old
Index: sys/i386/include/pmap.h
===================================================================
--- sys/i386/include/pmap.h
+++ sys/i386/include/pmap.h
@@ -376,7 +376,7 @@
* vtopte().
*/
void pmap_bootstrap(vm_paddr_t);
-int pmap_cache_bits(int mode, boolean_t is_pde);
+int pmap_cache_bits(pmap_t, int mode, boolean_t is_pde);
int pmap_change_attr(vm_offset_t, vm_size_t, int);
void pmap_init_pat(void);
void pmap_kenter(vm_offset_t va, vm_paddr_t pa);
Index: sys/mips/include/cca.h
===================================================================
--- /dev/null
+++ sys/mips/include/cca.h
@@ -0,0 +1,153 @@
+/* $NetBSD: cpuregs.h,v 1.70 2006/05/15 02:26:54 simonb Exp $ */
+
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)machConst.h 8.1 (Berkeley) 6/10/93
+ *
+ * machConst.h --
+ *
+ * Machine dependent constants.
+ *
+ * Copyright (C) 1989 Digital Equipment Corporation.
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies.
+ * Digital Equipment Corporation makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machConst.h,
+ * v 9.2 89/10/21 15:55:22 jhh Exp SPRITE (DECWRL)
+ * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAddrs.h,
+ * v 1.2 89/08/15 18:28:21 rab Exp SPRITE (DECWRL)
+ * from: Header: /sprite/src/kernel/vm/ds3100.md/RCS/vmPmaxConst.h,
+ * v 9.1 89/09/18 17:33:00 shirriff Exp SPRITE (DECWRL)
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MIPS_CCA_H_
+#define _MIPS_CCA_H_
+
+/*
+ * Cache Coherency Attributes:
+ * UC: Uncached.
+ * UA: Uncached accelerated.
+ * C: Cacheable, coherency unspecified.
+ * CNC: Cacheable non-coherent.
+ * CC: Cacheable coherent.
+ * CCS: Cacheable coherent, shared read.
+ * CCE: Cacheable coherent, exclusive read.
+ * CCEW: Cacheable coherent, exclusive write.
+ * CCUOW: Cacheable coherent, update on write.
+ *
+ * Note that some bits vary in meaning across implementations (and that the
+ * listing here is no doubt incomplete) and that the optimal cached mode varies
+ * between implementations. 0x02 is required to be UC and 0x03 is required to
+ * be a least C.
+ *
+ * We define the following logical bits:
+ * UNCACHED:
+ * The optimal uncached mode for the target CPU type. This must
+ * be suitable for use in accessing memory-mapped devices.
+ * CACHED: The optional cached mode for the target CPU type.
+ */
+
+#define MIPS_CCA_UC 0x02 /* Uncached. */
+#define MIPS_CCA_C 0x03 /* Cacheable, coherency unspecified. */
+
+#if defined(CPU_R4000) || defined(CPU_R10000)
+#define MIPS_CCA_CNC 0x03
+#define MIPS_CCA_CCE 0x04
+#define MIPS_CCA_CCEW 0x05
+
+#ifdef CPU_R4000
+#define MIPS_CCA_CCUOW 0x06
+#endif
+
+#ifdef CPU_R10000
+#define MIPS_CCA_UA 0x07
+#endif
+
+#define MIPS_CCA_CACHED MIPS_CCA_CCEW
+#endif /* defined(CPU_R4000) || defined(CPU_R10000) */
+
+#if defined(CPU_SB1)
+#define MIPS_CCA_CC 0x05 /* Cacheable Coherent. */
+#endif
+
+#if defined(CPU_MIPS74K)
+#define MIPS_CCA_UNCACHED 0x02
+#define MIPS_CCA_CACHED 0x03
+#endif
+
+/*
+ * 1004K and 1074K cores, as well as interAptiv and proAptiv cores, support
+ * Cacheable Coherent CCAs 0x04 and 0x05, as well as Cacheable non-Coherent
+ * CCA 0x03 and Uncached Accelerated CCA 0x07
+ */
+#if defined(CPU_MIPS1004K) || defined(CPU_MIPS1074K) || \
+ defined(CPU_INTERAPTIV) || defined(CPU_PROAPTIV)
+#define MIPS_CCA_CNC 0x03
+#define MIPS_CCA_CCE 0x04
+#define MIPS_CCA_CCS 0x05
+#define MIPS_CCA_UA 0x07
+
+/* We use shared read CCA for CACHED CCA */
+#define MIPS_CCA_CACHED MIPS_CCA_CCS
+#endif
+
+#if defined(CPU_XBURST)
+#define MIPS_CCA_UA 0x01
+#define MIPS_CCA_WC MIPS_CCA_UA
+#endif
+
+#ifndef MIPS_CCA_UNCACHED
+#define MIPS_CCA_UNCACHED MIPS_CCA_UC
+#endif
+
+/*
+ * If we don't know which cached mode to use and there is a cache coherent
+ * mode, use it. If there is not a cache coherent mode, use the required
+ * cacheable mode.
+ */
+#ifndef MIPS_CCA_CACHED
+#ifdef MIPS_CCA_CC
+#define MIPS_CCA_CACHED MIPS_CCA_CC
+#else
+#define MIPS_CCA_CACHED MIPS_CCA_C
+#endif
+#endif
+
+#endif
Index: sys/mips/include/cpuregs.h
===================================================================
--- sys/mips/include/cpuregs.h
+++ sys/mips/include/cpuregs.h
@@ -60,6 +60,10 @@
#ifndef _MIPS_CPUREGS_H_
#define _MIPS_CPUREGS_H_
+#ifndef _KVM_MINIDUMP
+#include <machine/cca.h>
+#endif
+
/*
* Address space.
* 32-bit mips CPUS partition their 32-bit address space into four segments:
@@ -105,96 +109,6 @@
#define MIPS_IS_VALID_PTR(x) (MIPS_IS_KSEG0_ADDR(x) || \
MIPS_IS_KSEG1_ADDR(x))
-/*
- * Cache Coherency Attributes:
- * UC: Uncached.
- * UA: Uncached accelerated.
- * C: Cacheable, coherency unspecified.
- * CNC: Cacheable non-coherent.
- * CC: Cacheable coherent.
- * CCS: Cacheable coherent, shared read.
- * CCE: Cacheable coherent, exclusive read.
- * CCEW: Cacheable coherent, exclusive write.
- * CCUOW: Cacheable coherent, update on write.
- *
- * Note that some bits vary in meaning across implementations (and that the
- * listing here is no doubt incomplete) and that the optimal cached mode varies
- * between implementations. 0x02 is required to be UC and 0x03 is required to
- * be a least C.
- *
- * We define the following logical bits:
- * UNCACHED:
- * The optimal uncached mode for the target CPU type. This must
- * be suitable for use in accessing memory-mapped devices.
- * CACHED: The optional cached mode for the target CPU type.
- */
-
-#define MIPS_CCA_UC 0x02 /* Uncached. */
-#define MIPS_CCA_C 0x03 /* Cacheable, coherency unspecified. */
-
-#if defined(CPU_R4000) || defined(CPU_R10000)
-#define MIPS_CCA_CNC 0x03
-#define MIPS_CCA_CCE 0x04
-#define MIPS_CCA_CCEW 0x05
-
-#ifdef CPU_R4000
-#define MIPS_CCA_CCUOW 0x06
-#endif
-
-#ifdef CPU_R10000
-#define MIPS_CCA_UA 0x07
-#endif
-
-#define MIPS_CCA_CACHED MIPS_CCA_CCEW
-#endif /* defined(CPU_R4000) || defined(CPU_R10000) */
-
-#if defined(CPU_SB1)
-#define MIPS_CCA_CC 0x05 /* Cacheable Coherent. */
-#endif
-
-#if defined(CPU_MIPS74K)
-#define MIPS_CCA_UNCACHED 0x02
-#define MIPS_CCA_CACHED 0x03
-#endif
-
-/*
- * 1004K and 1074K cores, as well as interAptiv and proAptiv cores, support
- * Cacheable Coherent CCAs 0x04 and 0x05, as well as Cacheable non-Coherent
- * CCA 0x03 and Uncached Accelerated CCA 0x07
- */
-#if defined(CPU_MIPS1004K) || defined(CPU_MIPS1074K) || \
- defined(CPU_INTERAPTIV) || defined(CPU_PROAPTIV)
-#define MIPS_CCA_CNC 0x03
-#define MIPS_CCA_CCE 0x04
-#define MIPS_CCA_CCS 0x05
-#define MIPS_CCA_UA 0x07
-
-/* We use shared read CCA for CACHED CCA */
-#define MIPS_CCA_CACHED MIPS_CCA_CCS
-#endif
-
-#if defined(CPU_XBURST)
-#define MIPS_CCA_UA 0x01
-#define MIPS_CCA_WC MIPS_CCA_UA
-#endif
-
-#ifndef MIPS_CCA_UNCACHED
-#define MIPS_CCA_UNCACHED MIPS_CCA_UC
-#endif
-
-/*
- * If we don't know which cached mode to use and there is a cache coherent
- * mode, use it. If there is not a cache coherent mode, use the required
- * cacheable mode.
- */
-#ifndef MIPS_CCA_CACHED
-#ifdef MIPS_CCA_CC
-#define MIPS_CCA_CACHED MIPS_CCA_CC
-#else
-#define MIPS_CCA_CACHED MIPS_CCA_C
-#endif
-#endif
-
#define MIPS_PHYS_TO_XKPHYS(cca,x) \
((0x2ULL << 62) | ((unsigned long long)(cca) << 59) | (x))
#define MIPS_PHYS_TO_XKPHYS_CACHED(x) \
Index: sys/mips/include/vm.h
===================================================================
--- sys/mips/include/vm.h
+++ sys/mips/include/vm.h
@@ -32,6 +32,7 @@
#define _MACHINE_VM_H_
#include <machine/pte.h>
+#include <machine/cca.h>
/* Memory attributes. */
#define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)MIPS_CCA_UNCACHED)
Index: sys/mips/mips/pmap.c
===================================================================
--- sys/mips/mips/pmap.c
+++ sys/mips/mips/pmap.c
@@ -3641,3 +3641,19 @@
mips_dcache_wbinv_range(ova, size);
return 0;
}
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ switch (mode) {
+ case VM_MEMATTR_UNCACHEABLE:
+ case VM_MEMATTR_WRITE_BACK:
+#ifdef MIPS_CCA_WC
+ case VM_MEMATTR_WRITE_COMBINING:
+#endif
+ return (TRUE);
+ default:
+ return (FALSE);
+ }
+}
Index: sys/powerpc/powerpc/pmap_dispatch.c
===================================================================
--- sys/powerpc/powerpc/pmap_dispatch.c
+++ sys/powerpc/powerpc/pmap_dispatch.c
@@ -620,3 +620,21 @@
}
int unmapped_buf_allowed;
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ switch (mode) {
+ case VM_MEMATTR_DEFAULT:
+ case VM_MEMATTR_UNCACHEABLE:
+ case VM_MEMATTR_CACHEABLE:
+ case VM_MEMATTR_WRITE_COMBINING:
+ case VM_MEMATTR_WRITE_BACK:
+ case VM_MEMATTR_WRITE_THROUGH:
+ case VM_MEMATTR_PREFETCHABLE:
+ return (TRUE);
+ default:
+ return (FALSE);
+ }
+}
Index: sys/riscv/riscv/pmap.c
===================================================================
--- sys/riscv/riscv/pmap.c
+++ sys/riscv/riscv/pmap.c
@@ -3263,3 +3263,10 @@
}
}
}
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode >= VM_MEMATTR_DEVICE && mode <= VM_MEMATTR_WRITE_BACK);
+}
Index: sys/sparc64/sparc64/pmap.c
===================================================================
--- sys/sparc64/sparc64/pmap.c
+++ sys/sparc64/sparc64/pmap.c
@@ -2318,3 +2318,10 @@
{
}
+
+boolean_t
+pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
+{
+
+ return (mode == VM_MEMATTR_DEFAULT);
+}
Index: sys/sys/pciio.h
===================================================================
--- sys/sys/pciio.h
+++ sys/sys/pciio.h
@@ -138,11 +138,30 @@
struct pci_vpd_element *plvi_data;
};
+struct pci_bar_mmap {
+ void *pbm_map_base; /* (sometimes IN)/OUT mmaped base */
+ size_t pbm_map_length; /* mapped length of the BAR, multiple
+ of pages */
+ uint64_t pbm_bar_length; /* actual length of the BAR */
+ int pbm_bar_off; /* offset from the mapped base to the
+ start of BAR */
+ struct pcisel pbm_sel; /* device to operate on */
+ int pbm_reg; /* starting address of BAR */
+ int pbm_flags;
+ int pbm_memattr;
+};
+
+#define PCIIO_BAR_MMAP_FIXED 0x01
+#define PCIIO_BAR_MMAP_EXCL 0x02
+#define PCIIO_BAR_MMAP_RW 0x04
+#define PCIIO_BAR_MMAP_ACTIVATE 0x08
+
#define PCIOCGETCONF _IOWR('p', 5, struct pci_conf_io)
#define PCIOCREAD _IOWR('p', 2, struct pci_io)
#define PCIOCWRITE _IOWR('p', 3, struct pci_io)
#define PCIOCATTACHED _IOWR('p', 4, struct pci_io)
#define PCIOCGETBAR _IOWR('p', 6, struct pci_bar_io)
#define PCIOCLISTVPD _IOWR('p', 7, struct pci_list_vpd_io)
+#define PCIOCBARMMAP _IOWR('p', 8, struct pci_bar_mmap)
#endif /* !_SYS_PCIIO_H_ */
Index: sys/vm/pmap.h
===================================================================
--- sys/vm/pmap.h
+++ sys/vm/pmap.h
@@ -142,6 +142,7 @@
boolean_t pmap_is_modified(vm_page_t m);
boolean_t pmap_is_prefaultable(pmap_t pmap, vm_offset_t va);
boolean_t pmap_is_referenced(vm_page_t m);
+boolean_t pmap_is_valid_memattr(pmap_t, vm_memattr_t);
vm_offset_t pmap_map(vm_offset_t *, vm_paddr_t, vm_paddr_t, int);
int pmap_mincore(pmap_t pmap, vm_offset_t addr,
vm_paddr_t *locked_pa);
Index: usr.sbin/pciconf/pciconf.8
===================================================================
--- usr.sbin/pciconf/pciconf.8
+++ usr.sbin/pciconf/pciconf.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 23, 2015
+.Dd June 14, 2018
.Dt PCICONF 8
.Os
.Sh NAME
@@ -40,6 +40,8 @@
.Fl r Oo Fl b | h Oc Ar device addr Ns Op : Ns Ar addr2
.Nm
.Fl w Oo Fl b | h Oc Ar device addr value
+.Nm
+.Fl D Oo Fl b | h | x Oc Ar device addr Op start Ns Op : Ns Ar count
.Sh DESCRIPTION
The
.Nm
@@ -305,17 +307,38 @@
.Ar addr
of device
.Ar selector .
-For both operations, the flags
-.Fl b
+.Pp
+The
+.Fl D
+option request a dump of the specified BAR.
+Dump is performed to the standard output, raw register values
+are written.
+Use
+.Xr hexdump 1
+to convert them to human-readable dump,
+or redirect into a file to save the snapshot of the device state.
+Optionally, the
+.Ar start
and
-.Fl h
+.Ar count
+of the registers dumped can be specified, in multiple of the operation width,
+see next paragraph.
+.Pp
+For read, write, and dump operations, the flags
+.Fl b ,
+.Fl h ,
+and
+.Fl x
select the width of the operation;
.Fl b
indicates a byte operation, and
.Fl h
indicates a halfword (two-byte) operation.
+.Fl x
+indicates a quadword (four-byte) operation.
The default is to read or
write a longword (four bytes).
+The quadword mode is only valid for BAR dump.
.Sh ENVIRONMENT
PCI vendor and device information is read from
.Pa /usr/local/share/pciids/pci.ids .
@@ -368,3 +391,11 @@
registers may cause a failure in badly designed
.Tn PCI
chips.
+.Pp
+There is currently no way to specify the caching mode for the mapping
+established by the
+.Fl D
+option,
+.Nm
+always uses uncached access.
+This is fine for control register BARs.
Index: usr.sbin/pciconf/pciconf.c
===================================================================
--- usr.sbin/pciconf/pciconf.c
+++ usr.sbin/pciconf/pciconf.c
@@ -34,6 +34,13 @@
#include <sys/types.h>
#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/pciio.h>
+#include <sys/queue.h>
+
+#include <vm/vm.h>
+
+#include <dev/pci/pcireg.h>
#include <assert.h>
#include <ctype.h>
@@ -44,10 +51,6 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <sys/pciio.h>
-#include <sys/queue.h>
-
-#include <dev/pci/pcireg.h>
#include "pathnames.h"
#include "pciconf.h"
@@ -82,32 +85,37 @@
static void readit(const char *, const char *, int);
static void writeit(const char *, const char *, const char *, int);
static void chkattached(const char *);
+static void dump_bar(const char *name, const char *reg, const char *bar_start,
+ const char *bar_count, int width, int verbose);
static int exitstatus = 0;
static void
usage(void)
{
- fprintf(stderr, "%s\n%s\n%s\n%s\n",
- "usage: pciconf -l [-BbcevV] [device]",
- " pciconf -a device",
- " pciconf -r [-b | -h] device addr[:addr2]",
- " pciconf -w [-b | -h] device addr value");
- exit (1);
+
+ fprintf(stderr, "%s",
+ "usage: pciconf -l [-BbcevV] [device]\n"
+ " pciconf -a device\n"
+ " pciconf -r [-b | -h] device addr[:addr2]\n"
+ " pciconf -w [-b | -h] device addr value\n"
+ " pciconf -D [-b | -h | -x] device bar [start [count]]"
+ "\n");
+ exit(1);
}
int
main(int argc, char **argv)
{
- int c;
- int listmode, readmode, writemode, attachedmode;
+ int c, width;
+ int listmode, readmode, writemode, attachedmode, dumpbarmode;
int bars, bridge, caps, errors, verbose, vpd;
- int byte, isshort;
- listmode = readmode = writemode = attachedmode = 0;
- bars = bridge = caps = errors = verbose = vpd = byte = isshort = 0;
+ listmode = readmode = writemode = attachedmode = dumpbarmode = 0;
+ bars = bridge = caps = errors = verbose = vpd= 0;
+ width = 4;
- while ((c = getopt(argc, argv, "aBbcehlrwVv")) != -1) {
+ while ((c = getopt(argc, argv, "aBbcDehlrwVv")) != -1) {
switch(c) {
case 'a':
attachedmode = 1;
@@ -119,19 +127,23 @@
case 'b':
bars = 1;
- byte = 1;
+ width = 1;
break;
case 'c':
caps = 1;
break;
+ case 'D':
+ dumpbarmode = 1;
+ break;
+
case 'e':
errors = 1;
break;
case 'h':
- isshort = 1;
+ width = 2;
break;
case 'l':
@@ -154,6 +166,10 @@
vpd = 1;
break;
+ case 'x':
+ width = 8;
+ break;
+
default:
usage();
}
@@ -162,7 +178,9 @@
if ((listmode && optind >= argc + 1)
|| (writemode && optind + 3 != argc)
|| (readmode && optind + 2 != argc)
- || (attachedmode && optind + 1 != argc))
+ || (attachedmode && optind + 1 != argc)
+ || (dumpbarmode && (optind + 2 > argc || optind + 4 < argc))
+ || (width == 8 && !dumpbarmode))
usage();
if (listmode) {
@@ -171,16 +189,20 @@
} else if (attachedmode) {
chkattached(argv[optind]);
} else if (readmode) {
- readit(argv[optind], argv[optind + 1],
- byte ? 1 : isshort ? 2 : 4);
+ readit(argv[optind], argv[optind + 1], width);
} else if (writemode) {
writeit(argv[optind], argv[optind + 1], argv[optind + 2],
- byte ? 1 : isshort ? 2 : 4);
+ width);
+ } else if (dumpbarmode) {
+ dump_bar(argv[optind], argv[optind + 1],
+ optind + 2 < argc ? argv[optind + 2] : NULL,
+ optind + 3 < argc ? argv[optind + 3] : NULL,
+ width, verbose);
} else {
usage();
}
- return exitstatus;
+ return (exitstatus);
}
static void
@@ -1027,3 +1049,117 @@
printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
close(fd);
}
+
+static void
+dump_bar(const char *name, const char *reg, const char *bar_start,
+ const char *bar_count, int width, int verbose)
+{
+ struct pci_bar_mmap pbm;
+ uint32_t *dd;
+ uint16_t *dh;
+ uint8_t *db;
+ uint64_t *dx, a, start, count;
+ char *el;
+ size_t res;
+ int fd;
+
+ start = 0;
+ if (bar_start != NULL) {
+ start = strtoul(bar_start, &el, 0);
+ if (*el != '\0')
+ errx(1, "Invalid bar start specification %s",
+ bar_start);
+ }
+ count = 0;
+ if (bar_count != NULL) {
+ count = strtoul(bar_count, &el, 0);
+ if (*el != '\0')
+ errx(1, "Invalid count specification %s",
+ bar_count);
+ }
+
+ pbm.pbm_sel = getsel(name);
+ pbm.pbm_reg = strtoul(reg, &el, 0);
+ if (*reg == '\0' || *el != '\0')
+ errx(1, "Invalid bar specification %s", reg);
+ pbm.pbm_flags = 0;
+ pbm.pbm_memattr = VM_MEMATTR_UNCACHEABLE; /* XXX */
+
+ fd = open(_PATH_DEVPCI, O_RDONLY, 0);
+ if (fd < 0)
+ err(1, "%s", _PATH_DEVPCI);
+
+ if (ioctl(fd, PCIOCBARMMAP, &pbm) < 0)
+ err(1, "ioctl(PCIOCBARMMAP)");
+
+ if (count == 0)
+ count = pbm.pbm_bar_length / width;
+ if (start + count < start || (start + count) * width < (uint64_t)width)
+ errx(1, "(start + count) x width overflow");
+ if ((start + count) * width > pbm.pbm_bar_length) {
+ if (start * width > pbm.pbm_bar_length)
+ count = 0;
+ else
+ count = (pbm.pbm_bar_length - start * width) / width;
+ }
+ if (verbose) {
+ fprintf(stderr,
+ "Dumping pci%d:%d:%d:%d BAR %x mapped base %p "
+ "off %#x length %#jx from %#jx count %#jx in %d-bytes\n",
+ pbm.pbm_sel.pc_domain, pbm.pbm_sel.pc_bus,
+ pbm.pbm_sel.pc_dev, pbm.pbm_sel.pc_func,
+ pbm.pbm_reg, pbm.pbm_map_base, pbm.pbm_bar_off,
+ pbm.pbm_bar_length, start, count, width);
+ }
+ switch (width) {
+ case 1:
+ db = (uint8_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+ pbm.pbm_bar_off + start * width);
+ for (a = 0; a < count; a += width, db++) {
+ res = fwrite(db, width, 1, stdout);
+ if (res != 1) {
+ errx(1, "error writing to stdout");
+ break;
+ }
+ }
+ break;
+ case 2:
+ dh = (uint16_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+ pbm.pbm_bar_off + start * width);
+ for (a = 0; a < count; a += width, dh++) {
+ res = fwrite(dh, width, 1, stdout);
+ if (res != 1) {
+ errx(1, "error writing to stdout");
+ break;
+ }
+ }
+ break;
+ case 4:
+ dd = (uint32_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+ pbm.pbm_bar_off + start * width);
+ for (a = 0; a < count; a += width) {
+ res = fwrite(dd, width, 1, stdout);
+ if (res != 1) {
+ errx(1, "error writing to stdout");
+ break;
+ }
+ }
+ break;
+ case 8:
+ dx = (uint64_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+ pbm.pbm_bar_off + start * width);
+ for (a = 0; a < count; a += width, dx++) {
+ res = fwrite(dx, width, 1, stdout);
+ if (res != 1) {
+ errx(1, "error writing to stdout");
+ break;
+ }
+ }
+ break;
+ default:
+ errx(1, "invalid access width");
+ }
+
+ munmap((void *)pbm.pbm_map_base, pbm.pbm_map_length);
+ close(fd);
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 22, 1:51 PM (9 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27850314
Default Alt Text
D15583.id44442.diff (39 KB)

Event Timeline