Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142620010
D15583.id44442.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
D15583.id44442.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D15583: Mmap device BAR into userspace.
Attached
Detach File
Event Timeline
Log In to Comment