diff options
Diffstat (limited to 'sys')
168 files changed, 3262 insertions, 4574 deletions
diff --git a/sys/amd64/amd64/efirt_machdep.c b/sys/amd64/amd64/efirt_machdep.c index 81a28ebe97ee..fe5d60c978dd 100644 --- a/sys/amd64/amd64/efirt_machdep.c +++ b/sys/amd64/amd64/efirt_machdep.c @@ -56,6 +56,13 @@ #include <vm/vm_pager.h> #include <vm/vm_radix.h> +/* The EFI regions we're allowed to map. */ +#define EFI_ALLOWED_TYPES_MASK ( \ + 1u << EFI_MD_TYPE_BS_CODE | 1u << EFI_MD_TYPE_BS_DATA | \ + 1u << EFI_MD_TYPE_RT_CODE | 1u << EFI_MD_TYPE_RT_DATA | \ + 1u << EFI_MD_TYPE_FIRMWARE \ +) + static pml5_entry_t *efi_pml5; static pml4_entry_t *efi_pml4; static vm_object_t obj_1t1_pt; @@ -181,6 +188,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz) vm_offset_t va; uint64_t idx; int bits, i, mode; + bool map_pz = true; obj_1t1_pt = vm_pager_allocate(OBJT_PHYS, NULL, ptoa(1 + NPML4EPG + NPML4EPG * NPDPEPG + NPML4EPG * NPDPEPG * NPDEPG), @@ -198,9 +206,16 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz) pmap_pinit_pml4(efi_pmltop_page); } + if ((efi_map_regs & ~EFI_ALLOWED_TYPES_MASK) != 0) { + printf("Ignoring the following runtime EFI regions: %#x\n", + efi_map_regs & ~EFI_ALLOWED_TYPES_MASK); + efi_map_regs &= EFI_ALLOWED_TYPES_MASK; + } + for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p, descsz)) { - if ((p->md_attr & EFI_MD_ATTR_RT) == 0) + if ((p->md_attr & EFI_MD_ATTR_RT) == 0 && + !EFI_MAP_BOOTTYPE_ALLOWED(p->md_type)) continue; if (p->md_virt != 0 && p->md_virt != p->md_phys) { if (bootverbose) @@ -256,6 +271,22 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz) } } VM_OBJECT_WUNLOCK(obj_1t1_pt); + if (p->md_phys == 0) + map_pz = false; + } + + /* + * Some BIOSes tend to access phys 0 during efirt calls, + * so map it if we haven't yet. + */ + if (map_pz) { + VM_OBJECT_WLOCK(obj_1t1_pt); + pte = efi_1t1_pte(0); + /* Assume Write-Back */ + bits = pmap_cache_bits(kernel_pmap, VM_MEMATTR_WRITE_BACK, + false) | X86_PG_RW | X86_PG_V; + pte_store(pte, bits); + VM_OBJECT_WUNLOCK(obj_1t1_pt); } return (true); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 032a134bbd4b..f46462b39fa3 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -188,6 +188,12 @@ struct init_ops init_ops = { */ vm_paddr_t efi_systbl_phys; +/* + * Bitmap of extra EFI memory region types that should be preserved and mapped + * during runtime services calls. + */ +uint32_t efi_map_regs; + /* Intel ICH registers */ #define ICH_PMBASE 0x400 #define ICH_SMI_EN ICH_PMBASE + 0x30 @@ -645,7 +651,7 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap, * NB: physmap_idx points to the next free slot. */ insert_idx = physmap_idx; - for (i = 0; i <= physmap_idx; i += 2) { + for (i = 0; i < physmap_idx; i += 2) { if (base < physmap[i + 1]) { if (base + length <= physmap[i]) { insert_idx = i; @@ -659,7 +665,7 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap, } /* See if we can prepend to the next entry. */ - if (insert_idx <= physmap_idx && base + length == physmap[insert_idx]) { + if (insert_idx < physmap_idx && base + length == physmap[insert_idx]) { physmap[insert_idx] = base; return (1); } @@ -670,8 +676,6 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap, return (1); } - physmap_idx += 2; - *physmap_idxp = physmap_idx; if (physmap_idx == PHYS_AVAIL_ENTRIES) { printf( "Too many segments in the physical address map, giving up\n"); @@ -682,11 +686,14 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap, * Move the last 'N' entries down to make room for the new * entry if needed. */ - for (i = (physmap_idx - 2); i > insert_idx; i -= 2) { + for (i = physmap_idx; i > insert_idx; i -= 2) { physmap[i] = physmap[i - 2]; physmap[i + 1] = physmap[i - 1]; } + physmap_idx += 2; + *physmap_idxp = physmap_idx; + /* Insert the new entry. */ physmap[insert_idx] = base; physmap[insert_idx + 1] = base + length; @@ -757,6 +764,7 @@ add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap, printf("%23s %12s %12s %8s %4s\n", "Type", "Physical", "Virtual", "#Pages", "Attr"); + TUNABLE_INT_FETCH("machdep.efirt.regs", &efi_map_regs); for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p, efihdr->descriptor_size)) { if (boothowto & RB_VERBOSE) { @@ -794,10 +802,13 @@ add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap, } switch (p->md_type) { - case EFI_MD_TYPE_CODE: - case EFI_MD_TYPE_DATA: case EFI_MD_TYPE_BS_CODE: case EFI_MD_TYPE_BS_DATA: + if (EFI_MAP_BOOTTYPE_ALLOWED(p->md_type)) + continue; + /* FALLTHROUGH */ + case EFI_MD_TYPE_CODE: + case EFI_MD_TYPE_DATA: case EFI_MD_TYPE_FREE: /* * We're allowed to use any entry with these types. diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c index 413b7c74890e..851f2df0e6e1 100644 --- a/sys/amd64/amd64/mem.c +++ b/sys/amd64/amd64/mem.c @@ -105,8 +105,8 @@ memrw(struct cdev *dev, struct uio *uio, int flags) * PAGE_SIZE, the uiomove() call does not * access past the end of the direct map. */ - if (v >= DMAP_MIN_ADDRESS && - v < DMAP_MIN_ADDRESS + dmaplimit) { + if (v >= kva_layout.dmap_low && + v < kva_layout.dmap_high) { error = uiomove((void *)v, c, uio); break; } diff --git a/sys/amd64/amd64/minidump_machdep.c b/sys/amd64/amd64/minidump_machdep.c index 6d0917e16099..43bf81a991bf 100644 --- a/sys/amd64/amd64/minidump_machdep.c +++ b/sys/amd64/amd64/minidump_machdep.c @@ -186,7 +186,7 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state) * tables, so care must be taken to read each entry only once. */ pmapsize = 0; - for (va = VM_MIN_KERNEL_ADDRESS; va < kva_end; ) { + for (va = kva_layout.km_low; va < kva_end; ) { /* * We always write a page, even if it is zero. Each * page written corresponds to 1GB of space @@ -279,9 +279,9 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state) mdhdr.msgbufsize = mbp->msg_size; mdhdr.bitmapsize = round_page(BITSET_SIZE(vm_page_dump_pages)); mdhdr.pmapsize = pmapsize; - mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS; - mdhdr.dmapbase = DMAP_MIN_ADDRESS; - mdhdr.dmapend = DMAP_MAX_ADDRESS; + mdhdr.kernbase = kva_layout.km_low; + mdhdr.dmapbase = kva_layout.dmap_low; + mdhdr.dmapend = kva_layout.dmap_high; mdhdr.dumpavailsize = round_page(sizeof(dump_avail)); dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_AMD64_VERSION, @@ -323,7 +323,7 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state) /* Dump kernel page directory pages */ bzero(fakepd, sizeof(fakepd)); - for (va = VM_MIN_KERNEL_ADDRESS; va < kva_end; va += NBPDP) { + for (va = kva_layout.km_low; va < kva_end; va += NBPDP) { ii = pmap_pml4e_index(va); pml4 = (uint64_t *)PHYS_TO_DMAP(KPML4phys) + ii; pdp = (uint64_t *)PHYS_TO_DMAP(*pml4 & PG_FRAME); diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 0044f27729f6..2c7777e608b9 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -415,7 +415,7 @@ SYSCTL_INT(_machdep, OID_AUTO, nkpt, CTLFLAG_RD, &nkpt, 0, static int ndmpdp; vm_paddr_t dmaplimit; -vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS; +vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS_LA48; pt_entry_t pg_nx; static SYSCTL_NODE(_vm, OID_AUTO, pmap, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, @@ -475,11 +475,36 @@ _Static_assert(DMPML4I + NDMPML4E <= KMSANSHADPML4I, "direct map overflow"); static pml4_entry_t *kernel_pml4; static u_int64_t DMPDphys; /* phys addr of direct mapped level 2 */ static u_int64_t DMPDPphys; /* phys addr of direct mapped level 3 */ +static u_int64_t DMPML4phys; /* ... level 4, for la57 */ static int ndmpdpphys; /* number of DMPDPphys pages */ vm_paddr_t kernphys; /* phys addr of start of bootstrap data */ vm_paddr_t KERNend; /* and the end */ +struct kva_layout_s kva_layout = { + .kva_min = KV4ADDR(PML4PML4I, 0, 0, 0), + .dmap_low = KV4ADDR(DMPML4I, 0, 0, 0), + .dmap_high = KV4ADDR(DMPML4I + NDMPML4E, 0, 0, 0), + .lm_low = KV4ADDR(LMSPML4I, 0, 0, 0), + .lm_high = KV4ADDR(LMEPML4I + 1, 0, 0, 0), + .km_low = KV4ADDR(KPML4BASE, 0, 0, 0), + .km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1, + NPDEPG - 1, NPTEPG - 1), + .rec_pt = KV4ADDR(PML4PML4I, 0, 0, 0), +}; + +struct kva_layout_s kva_layout_la57 = { + .kva_min = KV5ADDR(NPML5EPG / 2, 0, 0, 0, 0), /* == rec_pt */ + .dmap_low = KV5ADDR(DMPML5I, 0, 0, 0, 0), + .dmap_high = KV5ADDR(DMPML5I + NDMPML5E, 0, 0, 0, 0), + .lm_low = KV4ADDR(LMSPML4I, 0, 0, 0), + .lm_high = KV4ADDR(LMEPML4I + 1, 0, 0, 0), + .km_low = KV4ADDR(KPML4BASE, 0, 0, 0), + .km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1, + NPDEPG - 1, NPTEPG - 1), + .rec_pt = KV5ADDR(PML5PML5I, 0, 0, 0, 0), +}; + /* * pmap_mapdev support pre initialization (i.e. console) */ @@ -549,8 +574,8 @@ static int pmap_flags = PMAP_PDE_SUPERPAGE; /* flags for x86 pmaps */ static vmem_t *large_vmem; static u_int lm_ents; -#define PMAP_ADDRESS_IN_LARGEMAP(va) ((va) >= LARGEMAP_MIN_ADDRESS && \ - (va) < LARGEMAP_MIN_ADDRESS + NBPML4 * (u_long)lm_ents) +#define PMAP_ADDRESS_IN_LARGEMAP(va) ((va) >= kva_layout.lm_low && \ + (va) < kva_layout.lm_high) int pmap_pcid_enabled = 1; SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, @@ -1301,6 +1326,8 @@ static int pmap_change_props_locked(vm_offset_t va, vm_size_t size, static bool pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va); static bool pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp); +static bool pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, + vm_offset_t va, struct rwlock **lockp, vm_page_t mpte); static bool pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va, vm_page_t m); static int pmap_enter_2mpage(pmap_t pmap, vm_offset_t va, vm_page_t m, @@ -1334,7 +1361,7 @@ static pdp_entry_t *pmap_pti_pdpe(vm_offset_t va); static pd_entry_t *pmap_pti_pde(vm_offset_t va); static void pmap_pti_wire_pte(void *pte); static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, - bool remove_pt, struct spglist *free, struct rwlock **lockp); + bool demote_kpde, struct spglist *free, struct rwlock **lockp); static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t sva, pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp); static vm_page_t pmap_remove_pt_page(pmap_t pmap, vm_offset_t va); @@ -1720,7 +1747,7 @@ create_pagetables(vm_paddr_t *firstaddr) { pd_entry_t *pd_p; pdp_entry_t *pdp_p; - pml4_entry_t *p4_p; + pml4_entry_t *p4_p, *p4d_p; pml5_entry_t *p5_p; uint64_t DMPDkernphys; vm_paddr_t pax; @@ -1730,7 +1757,7 @@ create_pagetables(vm_paddr_t *firstaddr) vm_offset_t kasankernbase; int kasankpdpi, kasankpdi, nkasanpte; #endif - int i, j, ndm1g, nkpdpe, nkdmpde; + int i, j, ndm1g, nkpdpe, nkdmpde, ndmpml4phys; TSENTER(); /* Allocate page table pages for the direct map */ @@ -1738,15 +1765,30 @@ create_pagetables(vm_paddr_t *firstaddr) if (ndmpdp < 4) /* Minimum 4GB of dirmap */ ndmpdp = 4; ndmpdpphys = howmany(ndmpdp, NPDPEPG); - if (ndmpdpphys > NDMPML4E) { - /* - * Each NDMPML4E allows 512 GB, so limit to that, - * and then readjust ndmpdp and ndmpdpphys. - */ - printf("NDMPML4E limits system to %d GB\n", NDMPML4E * 512); - Maxmem = atop(NDMPML4E * NBPML4); - ndmpdpphys = NDMPML4E; - ndmpdp = NDMPML4E * NPDEPG; + if (la57) { + ndmpml4phys = howmany(ndmpdpphys, NPML4EPG); + if (ndmpml4phys > NDMPML5E) { + printf("NDMPML5E limits system to %ld GB\n", + (u_long)NDMPML5E * NBPML5 / 1024 / 1024 / 1024); + Maxmem = atop(NDMPML5E * NBPML5); + ndmpml4phys = NDMPML5E; + ndmpdpphys = ndmpml4phys * NPML4EPG; + ndmpdp = ndmpdpphys * NPDEPG; + } + DMPML4phys = allocpages(firstaddr, ndmpml4phys); + } else { + if (ndmpdpphys > NDMPML4E) { + /* + * Each NDMPML4E allows 512 GB, so limit to + * that, and then readjust ndmpdp and + * ndmpdpphys. + */ + printf("NDMPML4E limits system to %d GB\n", + NDMPML4E * 512); + Maxmem = atop(NDMPML4E * NBPML4); + ndmpdpphys = NDMPML4E; + ndmpdp = NDMPML4E * NPDEPG; + } } DMPDPphys = allocpages(firstaddr, ndmpdpphys); ndm1g = 0; @@ -1771,7 +1813,13 @@ create_pagetables(vm_paddr_t *firstaddr) dmaplimit = (vm_paddr_t)ndmpdp << PDPSHIFT; /* Allocate pages. */ + if (la57) { + KPML5phys = allocpages(firstaddr, 1); + p5_p = (pml5_entry_t *)KPML5phys; + } KPML4phys = allocpages(firstaddr, 1); + p4_p = (pml4_entry_t *)KPML4phys; + KPDPphys = allocpages(firstaddr, NKPML4E); #ifdef KASAN KASANPDPphys = allocpages(firstaddr, NKASANPML4E); @@ -1891,6 +1939,16 @@ create_pagetables(vm_paddr_t *firstaddr) } /* + * Connect the Direct Map slots up to the PML4. + * pml5 entries for DMAP are handled below in global pml5 loop. + */ + p4d_p = la57 ? (pml4_entry_t *)DMPML4phys : &p4_p[DMPML4I]; + for (i = 0; i < ndmpdpphys; i++) { + p4d_p[i] = (DMPDPphys + ptoa(i)) | X86_PG_RW | X86_PG_V | + pg_nx; + } + + /* * Instead of using a 1G page for the memory containing the kernel, * use 2M pages with read-only and no-execute permissions. (If using 1G * pages, this will partially overwrite the PDPEs above.) @@ -1909,11 +1967,6 @@ create_pagetables(vm_paddr_t *firstaddr) } } - /* And recursively map PML4 to itself in order to get PTmap */ - p4_p = (pml4_entry_t *)KPML4phys; - p4_p[PML4PML4I] = KPML4phys; - p4_p[PML4PML4I] |= X86_PG_RW | X86_PG_V | pg_nx; - #ifdef KASAN /* Connect the KASAN shadow map slots up to the PML4. */ for (i = 0; i < NKASANPML4E; i++) { @@ -1936,25 +1989,15 @@ create_pagetables(vm_paddr_t *firstaddr) } #endif - /* Connect the Direct Map slots up to the PML4. */ - for (i = 0; i < ndmpdpphys; i++) { - p4_p[DMPML4I + i] = DMPDPphys + ptoa(i); - p4_p[DMPML4I + i] |= X86_PG_RW | X86_PG_V | pg_nx; - } - /* Connect the KVA slots up to the PML4 */ for (i = 0; i < NKPML4E; i++) { p4_p[KPML4BASE + i] = KPDPphys + ptoa(i); p4_p[KPML4BASE + i] |= X86_PG_RW | X86_PG_V; } - kernel_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(KPML4phys); - if (la57) { /* XXXKIB bootstrap KPML5phys page is lost */ - KPML5phys = allocpages(firstaddr, 1); - for (i = 0, p5_p = (pml5_entry_t *)KPML5phys; i < NPML5EPG; - i++) { + for (i = 0; i < NPML5EPG; i++) { if (i == PML5PML5I) { /* * Recursively map PML5 to itself in @@ -1962,6 +2005,10 @@ create_pagetables(vm_paddr_t *firstaddr) */ p5_p[i] = KPML5phys | X86_PG_RW | X86_PG_A | X86_PG_M | X86_PG_V | pg_nx; + } else if (i >= DMPML5I && i < DMPML5I + NDMPML5E) { + /* Connect DMAP pml4 pages to PML5. */ + p5_p[i] = (DMPML4phys + ptoa(i - DMPML5I)) | + X86_PG_RW | X86_PG_V | pg_nx; } else if (i == pmap_pml5e_index(UPT_MAX_ADDRESS)) { p5_p[i] = KPML4phys | X86_PG_RW | X86_PG_A | X86_PG_M | X86_PG_V; @@ -1969,6 +2016,10 @@ create_pagetables(vm_paddr_t *firstaddr) p5_p[i] = 0; } } + } else { + /* Recursively map PML4 to itself in order to get PTmap */ + p4_p[PML4PML4I] = KPML4phys; + p4_p[PML4PML4I] |= X86_PG_RW | X86_PG_V | pg_nx; } TSEXIT(); } @@ -2022,7 +2073,7 @@ pmap_bootstrap(vm_paddr_t *firstaddr) */ virtual_avail = (vm_offset_t)KERNSTART + round_2mpage(KERNend - (vm_paddr_t)kernphys); - virtual_end = VM_MAX_KERNEL_ADDRESS; + virtual_end = kva_layout.km_high; /* * Enable PG_G global pages, then switch to the kernel page @@ -2044,9 +2095,13 @@ pmap_bootstrap(vm_paddr_t *firstaddr) * Initialize the kernel pmap (which is statically allocated). * Count bootstrap data as being resident in case any of this data is * later unmapped (using pmap_remove()) and freed. + * + * DMAP_TO_PHYS()/PHYS_TO_DMAP() are functional only after + * kva_layout is fixed. */ PMAP_LOCK_INIT(kernel_pmap); if (la57) { + kva_layout = kva_layout_la57; vtoptem = ((1ul << (NPTEPGSHIFT + NPDEPGSHIFT + NPDPEPGSHIFT + NPML4EPGSHIFT + NPML5EPGSHIFT)) - 1) << 3; PTmap = (vm_offset_t)P5Tmap; @@ -2057,6 +2112,7 @@ pmap_bootstrap(vm_paddr_t *firstaddr) kernel_pmap->pm_cr3 = KPML5phys; pmap_pt_page_count_adj(kernel_pmap, 1); /* top-level page */ } else { + kernel_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(KPML4phys); kernel_pmap->pm_pmltop = kernel_pml4; kernel_pmap->pm_cr3 = KPML4phys; } @@ -2418,6 +2474,7 @@ pmap_init(void) { struct pmap_preinit_mapping *ppim; vm_page_t m, mpte; + pml4_entry_t *pml4e; int error, i, ret, skz63; /* L1TF, reserve page @0 unconditionally */ @@ -2557,18 +2614,19 @@ pmap_init(void) printf("pmap: large map %u PML4 slots (%lu GB)\n", lm_ents, (u_long)lm_ents * (NBPML4 / 1024 / 1024 / 1024)); if (lm_ents != 0) { - large_vmem = vmem_create("large", LARGEMAP_MIN_ADDRESS, - (vmem_size_t)lm_ents * NBPML4, PAGE_SIZE, 0, M_WAITOK); + large_vmem = vmem_create("large", kva_layout.lm_low, + (vmem_size_t)kva_layout.lm_high - kva_layout.lm_low, + PAGE_SIZE, 0, M_WAITOK); if (large_vmem == NULL) { printf("pmap: cannot create large map\n"); lm_ents = 0; } for (i = 0; i < lm_ents; i++) { m = pmap_large_map_getptp_unlocked(); - /* XXXKIB la57 */ - kernel_pml4[LMSPML4I + i] = X86_PG_V | - X86_PG_RW | X86_PG_A | X86_PG_M | pg_nx | - VM_PAGE_TO_PHYS(m); + pml4e = pmap_pml4e(kernel_pmap, kva_layout.lm_low + + (u_long)i * NBPML4); + *pml4e = X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M | + pg_nx | VM_PAGE_TO_PHYS(m); } } } @@ -3897,7 +3955,7 @@ pmap_kextract(vm_offset_t va) pd_entry_t pde; vm_paddr_t pa; - if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) { + if (va >= kva_layout.dmap_low && va < kva_layout.dmap_high) { pa = DMAP_TO_PHYS(va); } else if (PMAP_ADDRESS_IN_LARGEMAP(va)) { pa = pmap_large_map_kextract(va); @@ -4038,7 +4096,7 @@ pmap_qremove(vm_offset_t sva, int count) * enough to one of those pmap_enter() calls for it to * be caught up in a promotion. */ - KASSERT(va >= VM_MIN_KERNEL_ADDRESS, ("usermode va %lx", va)); + KASSERT(va >= kva_layout.km_low, ("usermode va %lx", va)); KASSERT((*vtopde(va) & X86_PG_PS) == 0, ("pmap_qremove on promoted va %#lx", va)); @@ -4326,21 +4384,13 @@ void pmap_pinit_pml5(vm_page_t pml5pg) { pml5_entry_t *pm_pml5; + int i; pm_pml5 = (pml5_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pml5pg)); - - /* - * Add pml5 entry at top of KVA pointing to existing pml4 table, - * entering all existing kernel mappings into level 5 table. - */ - pm_pml5[pmap_pml5e_index(UPT_MAX_ADDRESS)] = KPML4phys | X86_PG_V | - X86_PG_RW | X86_PG_A | X86_PG_M; - - /* - * Install self-referential address mapping entry. - */ - pm_pml5[PML5PML5I] = VM_PAGE_TO_PHYS(pml5pg) | - X86_PG_RW | X86_PG_V | X86_PG_M | X86_PG_A; + for (i = 0; i < NPML5EPG / 2; i++) + pm_pml5[i] = 0; + for (; i < NPML5EPG; i++) + pm_pml5[i] = kernel_pmap->pm_pmltop[i]; } static void @@ -4897,8 +4947,8 @@ pmap_release(pmap_t pmap) m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_pmltop)); if (pmap_is_la57(pmap)) { - pmap->pm_pmltop[pmap_pml5e_index(UPT_MAX_ADDRESS)] = 0; - pmap->pm_pmltop[PML5PML5I] = 0; + for (i = NPML5EPG / 2; i < NPML5EPG; i++) + pmap->pm_pmltop[i] = 0; } else { for (i = 0; i < NKPML4E; i++) /* KVA */ pmap->pm_pmltop[KPML4BASE + i] = 0; @@ -4940,7 +4990,7 @@ pmap_release(pmap_t pmap) static int kvm_size(SYSCTL_HANDLER_ARGS) { - unsigned long ksize = VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS; + unsigned long ksize = kva_layout.km_high - kva_layout.km_low; return sysctl_handle_long(oidp, &ksize, 0, req); } @@ -4951,7 +5001,7 @@ SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG | CTLFLAG_RD | CTLFLAG_MPSAFE, static int kvm_free(SYSCTL_HANDLER_ARGS) { - unsigned long kfree = VM_MAX_KERNEL_ADDRESS - kernel_vm_end; + unsigned long kfree = kva_layout.km_high - kernel_vm_end; return sysctl_handle_long(oidp, &kfree, 0, req); } @@ -5029,7 +5079,7 @@ pmap_page_array_startup(long pages) vm_page_array_size = pages; - start = VM_MIN_KERNEL_ADDRESS; + start = kva_layout.km_low; end = start + pages * sizeof(struct vm_page); for (va = start; va < end; va += NBPDR) { pfn = first_page + (va - start) / sizeof(struct vm_page); @@ -6011,11 +6061,17 @@ static bool pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp) { + return (pmap_demote_pde_mpte(pmap, pde, va, lockp, NULL)); +} + +static bool +pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, + struct rwlock **lockp, vm_page_t mpte) +{ pd_entry_t newpde, oldpde; pt_entry_t *firstpte, newpte; pt_entry_t PG_A, PG_G, PG_M, PG_PKU_MASK, PG_RW, PG_V; vm_paddr_t mptepa; - vm_page_t mpte; int PG_PTE_CACHE; bool in_kernel; @@ -6028,61 +6084,65 @@ pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, PG_PKU_MASK = pmap_pku_mask_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); - in_kernel = va >= VM_MAXUSER_ADDRESS; oldpde = *pde; KASSERT((oldpde & (PG_PS | PG_V)) == (PG_PS | PG_V), ("pmap_demote_pde: oldpde is missing PG_PS and/or PG_V")); - - /* - * Invalidate the 2MB page mapping and return "failure" if the - * mapping was never accessed. - */ - if ((oldpde & PG_A) == 0) { - KASSERT((oldpde & PG_W) == 0, - ("pmap_demote_pde: a wired mapping is missing PG_A")); - pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp); - return (false); - } - - mpte = pmap_remove_pt_page(pmap, va); + KASSERT((oldpde & PG_MANAGED) == 0 || lockp != NULL, + ("pmap_demote_pde: lockp for a managed mapping is NULL")); + in_kernel = va >= VM_MAXUSER_ADDRESS; if (mpte == NULL) { - KASSERT((oldpde & PG_W) == 0, - ("pmap_demote_pde: page table page for a wired mapping" - " is missing")); - - /* - * If the page table page is missing and the mapping - * is for a kernel address, the mapping must belong to - * the direct map. Page table pages are preallocated - * for every other part of the kernel address space, - * so the direct map region is the only part of the - * kernel address space that must be handled here. - */ - KASSERT(!in_kernel || (va >= DMAP_MIN_ADDRESS && - va < DMAP_MAX_ADDRESS), - ("pmap_demote_pde: No saved mpte for va %#lx", va)); - - /* - * If the 2MB page mapping belongs to the direct map - * region of the kernel's address space, then the page - * allocation request specifies the highest possible - * priority (VM_ALLOC_INTERRUPT). Otherwise, the - * priority is normal. - */ - mpte = pmap_alloc_pt_page(pmap, pmap_pde_pindex(va), - (in_kernel ? VM_ALLOC_INTERRUPT : 0) | VM_ALLOC_WIRED); - /* - * If the allocation of the new page table page fails, - * invalidate the 2MB page mapping and return "failure". + * Invalidate the 2MB page mapping and return "failure" if the + * mapping was never accessed. */ - if (mpte == NULL) { + if ((oldpde & PG_A) == 0) { + KASSERT((oldpde & PG_W) == 0, + ("pmap_demote_pde: a wired mapping is missing PG_A")); pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp); return (false); } - if (!in_kernel) - mpte->ref_count = NPTEPG; + mpte = pmap_remove_pt_page(pmap, va); + if (mpte == NULL) { + KASSERT((oldpde & PG_W) == 0, + ("pmap_demote_pde: page table page for a wired mapping is missing")); + + /* + * If the page table page is missing and the mapping + * is for a kernel address, the mapping must belong to + * the direct map. Page table pages are preallocated + * for every other part of the kernel address space, + * so the direct map region is the only part of the + * kernel address space that must be handled here. + */ + KASSERT(!in_kernel || (va >= kva_layout.dmap_low && + va < kva_layout.dmap_high), + ("pmap_demote_pde: No saved mpte for va %#lx", va)); + + /* + * If the 2MB page mapping belongs to the direct map + * region of the kernel's address space, then the page + * allocation request specifies the highest possible + * priority (VM_ALLOC_INTERRUPT). Otherwise, the + * priority is normal. + */ + mpte = pmap_alloc_pt_page(pmap, pmap_pde_pindex(va), + (in_kernel ? VM_ALLOC_INTERRUPT : 0) | + VM_ALLOC_WIRED); + + /* + * If the allocation of the new page table page fails, + * invalidate the 2MB page mapping and return "failure". + */ + if (mpte == NULL) { + pmap_demote_pde_abort(pmap, va, pde, oldpde, + lockp); + return (false); + } + + if (!in_kernel) + mpte->ref_count = NPTEPG; + } } mptepa = VM_PAGE_TO_PHYS(mpte); firstpte = (pt_entry_t *)PHYS_TO_DMAP(mptepa); @@ -6153,8 +6213,7 @@ pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, * pmap_remove_kernel_pde: Remove a kernel superpage mapping. */ static void -pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, - bool remove_pt) +pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va) { pd_entry_t newpde; vm_paddr_t mptepa; @@ -6162,12 +6221,8 @@ pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, KASSERT(pmap == kernel_pmap, ("pmap %p is not kernel_pmap", pmap)); PMAP_LOCK_ASSERT(pmap, MA_OWNED); - if (remove_pt) - mpte = pmap_remove_pt_page(pmap, va); - else - mpte = vm_radix_lookup(&pmap->pm_root, pmap_pde_pindex(va)); - if (mpte == NULL) - panic("pmap_remove_kernel_pde: Missing pt page."); + mpte = pmap_remove_pt_page(pmap, va); + KASSERT(mpte != NULL, ("pmap_remove_kernel_pde: missing pt page")); mptepa = VM_PAGE_TO_PHYS(mpte); newpde = mptepa | X86_PG_M | X86_PG_A | X86_PG_RW | X86_PG_V; @@ -6197,7 +6252,7 @@ pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, * pmap_remove_pde: do the things to unmap a superpage in a process */ static int -pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool remove_pt, +pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool demote_kpde, struct spglist *free, struct rwlock **lockp) { struct md_page *pvh; @@ -6237,9 +6292,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool remove_pt, pmap_delayed_invl_page(m); } } - if (pmap == kernel_pmap) { - pmap_remove_kernel_pde(pmap, pdq, sva, remove_pt); - } else { + if (pmap != kernel_pmap) { mpte = pmap_remove_pt_page(pmap, sva); if (mpte != NULL) { KASSERT(vm_page_any_valid(mpte), @@ -6250,6 +6303,14 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool remove_pt, mpte->ref_count = 0; pmap_add_delayed_free_list(mpte, free, false); } + } else if (demote_kpde) { + pmap_remove_kernel_pde(pmap, pdq, sva); + } else { + mpte = vm_radix_lookup(&pmap->pm_root, pmap_pde_pindex(sva)); + if (vm_page_any_valid(mpte)) { + mpte->valid = 0; + pmap_zero_page(mpte); + } } return (pmap_unuse_pt(pmap, sva, *pmap_pdpe(pmap, sva), free)); } @@ -7171,7 +7232,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, PG_RW = pmap_rw_bit(pmap); va = trunc_page(va); - KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); + KASSERT(va <= kva_layout.km_high, ("pmap_enter: toobig")); KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%lx)", va)); @@ -7561,8 +7622,8 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags, * the mapping is not from kernel_pmap, then * a reserved PT page could be freed. */ - (void)pmap_remove_pde(pmap, pde, va, - pmap != kernel_pmap, &free, lockp); + (void)pmap_remove_pde(pmap, pde, va, false, &free, + lockp); if ((oldpde & PG_G) == 0) pmap_invalidate_pde_page(pmap, va, oldpde); } else { @@ -7572,10 +7633,9 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags, * before any changes to mappings are * made. Abort on failure. */ - mt = PHYS_TO_VM_PAGE(*pde & PG_FRAME); - if (pmap_insert_pt_page(pmap, mt, false, false)) { - if (pdpg != NULL) - pdpg->ref_count--; + mt = PHYS_TO_VM_PAGE(oldpde & PG_FRAME); + if (pmap_insert_pt_page(pmap, mt, false, + false)) { CTR1(KTR_PMAP, "pmap_enter_pde: cannot ins kern ptp va %#lx", va); @@ -9538,7 +9598,7 @@ pmap_unmapdev(void *p, vm_size_t size) va = (vm_offset_t)p; /* If we gave a direct map region in pmap_mapdev, do nothing */ - if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) + if (va >= kva_layout.dmap_low && va < kva_layout.dmap_high) return; offset = va & PAGE_MASK; size = round_page(offset + size); @@ -9637,6 +9697,8 @@ pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va, vm_page_t m) void pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) { + if (m->md.pat_mode == ma) + return; m->md.pat_mode = ma; @@ -9656,6 +9718,9 @@ pmap_page_set_memattr_noflush(vm_page_t m, vm_memattr_t ma) { int error; + if (m->md.pat_mode == ma) + return; + m->md.pat_mode = ma; if ((m->flags & PG_FICTITIOUS) != 0) @@ -9712,7 +9777,7 @@ pmap_change_prot(vm_offset_t va, vm_size_t size, vm_prot_t prot) int error; /* Only supported within the kernel map. */ - if (va < VM_MIN_KERNEL_ADDRESS) + if (va < kva_layout.km_low) return (EINVAL); PMAP_LOCK(kernel_pmap); @@ -9743,7 +9808,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot, * Only supported on kernel virtual addresses, including the direct * map but excluding the recursive map. */ - if (base < DMAP_MIN_ADDRESS) + if (base < kva_layout.dmap_low) return (EINVAL); /* @@ -9766,7 +9831,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot, pte_bits |= X86_PG_RW; } if ((prot & VM_PROT_EXECUTE) == 0 || - va < VM_MIN_KERNEL_ADDRESS) { + va < kva_layout.km_low) { pde_bits |= pg_nx; pte_bits |= pg_nx; } @@ -9862,7 +9927,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot, pmap_pte_props(pdpe, pde_bits, pde_mask); changed = true; } - if (tmpva >= VM_MIN_KERNEL_ADDRESS && + if (tmpva >= kva_layout.km_low && (*pdpe & PG_PS_FRAME) < dmaplimit) { if (pa_start == pa_end) { /* Start physical address run. */ @@ -9892,7 +9957,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot, pmap_pte_props(pde, pde_bits, pde_mask); changed = true; } - if (tmpva >= VM_MIN_KERNEL_ADDRESS && + if (tmpva >= kva_layout.km_low && (*pde & PG_PS_FRAME) < dmaplimit) { if (pa_start == pa_end) { /* Start physical address run. */ @@ -9920,7 +9985,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot, pmap_pte_props(pte, pte_bits, pte_mask); changed = true; } - if (tmpva >= VM_MIN_KERNEL_ADDRESS && + if (tmpva >= kva_layout.km_low && (*pte & PG_FRAME) < dmaplimit) { if (pa_start == pa_end) { /* Start physical address run. */ @@ -9977,9 +10042,9 @@ pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate) { pdp_entry_t *pdpe; pd_entry_t *pde; - vm_page_t m; vm_offset_t va; - bool changed; + vm_page_t m, mpte; + bool changed, rv __diagused; if (len == 0) return; @@ -9998,14 +10063,19 @@ pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate) * x86_mr_split_dmap() function. */ m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_WAITOK); + if (len < NBPDR) { + mpte = vm_page_alloc_noobj(VM_ALLOC_WIRED | + VM_ALLOC_WAITOK); + } else + mpte = NULL; PMAP_LOCK(kernel_pmap); pdpe = pmap_pdpe(kernel_pmap, va); if ((*pdpe & X86_PG_V) == 0) panic("pmap_demote_DMAP: invalid PDPE"); if ((*pdpe & PG_PS) != 0) { - if (!pmap_demote_pdpe(kernel_pmap, pdpe, va, m)) - panic("pmap_demote_DMAP: PDPE failed"); + rv = pmap_demote_pdpe(kernel_pmap, pdpe, va, m); + KASSERT(rv, ("pmap_demote_DMAP: PDPE failed")); changed = true; m = NULL; } @@ -10014,9 +10084,13 @@ pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate) if ((*pde & X86_PG_V) == 0) panic("pmap_demote_DMAP: invalid PDE"); if ((*pde & PG_PS) != 0) { - if (!pmap_demote_pde(kernel_pmap, pde, va)) - panic("pmap_demote_DMAP: PDE failed"); + mpte->pindex = pmap_pde_pindex(va); + pmap_pt_page_count_adj(kernel_pmap, 1); + rv = pmap_demote_pde_mpte(kernel_pmap, pde, va, + NULL, mpte); + KASSERT(rv, ("pmap_demote_DMAP: PDE failed")); changed = true; + mpte = NULL; } } if (changed && invalidate) @@ -10026,6 +10100,10 @@ pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate) vm_page_unwire_noq(m); vm_page_free(m); } + if (mpte != NULL) { + vm_page_unwire_noq(mpte); + vm_page_free(mpte); + } } } @@ -10879,8 +10957,8 @@ pmap_large_unmap(void *svaa, vm_size_t len) struct spglist spgf; sva = (vm_offset_t)svaa; - if (len == 0 || sva + len < sva || (sva >= DMAP_MIN_ADDRESS && - sva + len <= DMAP_MIN_ADDRESS + dmaplimit)) + if (len == 0 || sva + len < sva || (sva >= kva_layout.dmap_low && + sva + len < kva_layout.dmap_high)) return; SLIST_INIT(&spgf); @@ -11126,11 +11204,10 @@ pmap_large_map_wb(void *svap, vm_size_t len) sva = (vm_offset_t)svap; eva = sva + len; pmap_large_map_wb_fence(); - if (sva >= DMAP_MIN_ADDRESS && eva <= DMAP_MIN_ADDRESS + dmaplimit) { + if (sva >= kva_layout.dmap_low && eva < kva_layout.dmap_high) { pmap_large_map_flush_range(sva, len); } else { - KASSERT(sva >= LARGEMAP_MIN_ADDRESS && - eva <= LARGEMAP_MIN_ADDRESS + lm_ents * NBPML4, + KASSERT(sva >= kva_layout.lm_low && eva < kva_layout.lm_high, ("pmap_large_map_wb: not largemap %#lx %#lx", sva, len)); pmap_large_map_wb_large(sva, eva); } @@ -11171,8 +11248,8 @@ pmap_pti_init(void) VM_OBJECT_WLOCK(pti_obj); pml4_pg = pmap_pti_alloc_page(); pti_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pml4_pg)); - for (va = VM_MIN_KERNEL_ADDRESS; va <= VM_MAX_KERNEL_ADDRESS && - va >= VM_MIN_KERNEL_ADDRESS && va > NBPML4; va += NBPML4) { + for (va = kva_layout.km_low; va <= kva_layout.km_high && + va >= kva_layout.km_low && va > NBPML4; va += NBPML4) { pdpe = pmap_pti_pdpe(va); pmap_pti_wire_pte(pdpe); } diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 09ac0a67dbef..eefddad2f142 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -769,7 +769,7 @@ trap_pfault(struct trapframe *frame, bool usermode, int *signo, int *ucode) return (-1); } } - if (eva >= VM_MIN_KERNEL_ADDRESS) { + if (eva >= kva_layout.km_low) { /* * Don't allow user-mode faults in kernel address space. */ diff --git a/sys/amd64/include/efi.h b/sys/amd64/include/efi.h index b47c4aa27ac7..439f2f0b317d 100644 --- a/sys/amd64/include/efi.h +++ b/sys/amd64/include/efi.h @@ -53,6 +53,10 @@ #define EFI_TIME_OWNED() mtx_assert(&atrtc_time_lock, MA_OWNED) #define EFI_RT_HANDLE_FAULTS_DEFAULT 1 + +#define EFI_MAP_BOOTTYPE_ALLOWED(type) (((efi_map_regs >> (type)) & 1) != 0) + +extern uint32_t efi_map_regs; #endif struct efirt_callinfo { diff --git a/sys/amd64/include/param.h b/sys/amd64/include/param.h index 8db314fa034d..1bbb302259d6 100644 --- a/sys/amd64/include/param.h +++ b/sys/amd64/include/param.h @@ -146,8 +146,9 @@ #define amd64_btop(x) ((unsigned long)(x) >> PAGE_SHIFT) #define amd64_ptob(x) ((unsigned long)(x) << PAGE_SHIFT) -#define INKERNEL(va) (((va) >= DMAP_MIN_ADDRESS && (va) < DMAP_MAX_ADDRESS) \ - || ((va) >= VM_MIN_KERNEL_ADDRESS && (va) < VM_MAX_KERNEL_ADDRESS)) +#define INKERNEL(va) \ + (((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_high) || \ + ((va) >= kva_layout.km_low && (va) < kva_layout.km_high)) #ifdef SMP #define SC_TABLESIZE 1024 /* Must be power of 2. */ diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h index 7d3e91bcd9b9..08e96027a5ed 100644 --- a/sys/amd64/include/pmap.h +++ b/sys/amd64/include/pmap.h @@ -169,11 +169,12 @@ * the recursive page table map. */ #define NDMPML4E 8 +#define NDMPML5E 32 /* - * These values control the layout of virtual memory. The starting address - * of the direct map, which is controlled by DMPML4I, must be a multiple of - * its size. (See the PHYS_TO_DMAP() and DMAP_TO_PHYS() macros.) + * These values control the layout of virtual memory. The starting + * address of the direct map is controlled by DMPML4I on LA48 and + * DMPML5I on LA57. * * Note: KPML4I is the index of the (single) level 4 page that maps * the KVA that holds KERNBASE, while KPML4BASE is the index of the @@ -191,6 +192,7 @@ #define KPML4BASE (NPML4EPG-NKPML4E) /* KVM at highest addresses */ #define DMPML4I rounddown(KPML4BASE-NDMPML4E, NDMPML4E) /* Below KVM */ +#define DMPML5I (NPML5EPG / 2 + 1) #define KPML4I (NPML4EPG-1) #define KPDPI (NPDPEPG-2) /* kernbase at -2GB */ @@ -548,6 +550,18 @@ pmap_pml5e_index(vm_offset_t va) return ((va >> PML5SHIFT) & ((1ul << NPML5EPGSHIFT) - 1)); } +struct kva_layout_s { + vm_offset_t kva_min; + vm_offset_t dmap_low; /* DMAP_MIN_ADDRESS */ + vm_offset_t dmap_high; /* DMAP_MAX_ADDRESS */ + vm_offset_t lm_low; /* LARGEMAP_MIN_ADDRESS */ + vm_offset_t lm_high; /* LARGEMAP_MAX_ADDRESS */ + vm_offset_t km_low; /* VM_MIN_KERNEL_ADDRESS */ + vm_offset_t km_high; /* VM_MAX_KERNEL_ADDRESS */ + vm_offset_t rec_pt; +}; +extern struct kva_layout_s kva_layout; + #endif /* !LOCORE */ #endif /* !_MACHINE_PMAP_H_ */ diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h index 0cd9bb4fa7a4..e4cc05cbb889 100644 --- a/sys/amd64/include/vmparam.h +++ b/sys/amd64/include/vmparam.h @@ -163,6 +163,7 @@ * Virtual addresses of things. Derived from the page directory and * page table indexes from pmap.h for precision. * + * LA48: * 0x0000000000000000 - 0x00007fffffffffff user map * 0x0000800000000000 - 0xffff7fffffffffff does not exist (hole) * 0xffff800000000000 - 0xffff804020100fff recursive page table (512GB slot) @@ -175,18 +176,29 @@ * 0xfffffc0000000000 - 0xfffffdffffffffff 2TB KMSAN shadow map, optional * 0xfffffe0000000000 - 0xffffffffffffffff 2TB kernel map * + * LA57: + * 0x0000000000000000 - 0x00ffffffffffffff user map + * 0x0100000000000000 - 0xf0ffffffffffffff does not exist (hole) + * 0xff00000000000000 - 0xff00ffffffffffff recursive page table (2048TB slot) + * 0xff01000000000000 - 0xff20ffffffffffff direct map (32 x 2048TB slots) + * 0xff21000000000000 - 0xffff807fffffffff unused + * 0xffff808000000000 - 0xffff847fffffffff large map (can be tuned up) + * 0xffff848000000000 - 0xfffff77fffffffff unused (large map extends there) + * 0xfffff60000000000 - 0xfffff7ffffffffff 2TB KMSAN origin map, optional + * 0xfffff78000000000 - 0xfffff7bfffffffff 512GB KASAN shadow map, optional + * 0xfffff80000000000 - 0xfffffbffffffffff 4TB unused + * 0xfffffc0000000000 - 0xfffffdffffffffff 2TB KMSAN shadow map, optional + * 0xfffffe0000000000 - 0xffffffffffffffff 2TB kernel map + * * Within the kernel map: * * 0xfffffe0000000000 vm_page_array * 0xffffffff80000000 KERNBASE */ -#define VM_MIN_KERNEL_ADDRESS KV4ADDR(KPML4BASE, 0, 0, 0) -#define VM_MAX_KERNEL_ADDRESS KV4ADDR(KPML4BASE + NKPML4E - 1, \ - NPDPEPG-1, NPDEPG-1, NPTEPG-1) - -#define DMAP_MIN_ADDRESS KV4ADDR(DMPML4I, 0, 0, 0) -#define DMAP_MAX_ADDRESS KV4ADDR(DMPML4I + NDMPML4E, 0, 0, 0) +#define VM_MIN_KERNEL_ADDRESS_LA48 KV4ADDR(KPML4BASE, 0, 0, 0) +#define VM_MIN_KERNEL_ADDRESS kva_layout.km_low +#define VM_MAX_KERNEL_ADDRESS kva_layout.km_high #define KASAN_MIN_ADDRESS KV4ADDR(KASANPML4I, 0, 0, 0) #define KASAN_MAX_ADDRESS KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0) @@ -199,9 +211,6 @@ #define KMSAN_ORIG_MAX_ADDRESS KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E, \ 0, 0, 0) -#define LARGEMAP_MIN_ADDRESS KV4ADDR(LMSPML4I, 0, 0, 0) -#define LARGEMAP_MAX_ADDRESS KV4ADDR(LMEPML4I + 1, 0, 0, 0) - /* * Formally kernel mapping starts at KERNBASE, but kernel linker * script leaves first PDE reserved. For legacy BIOS boot, kernel is @@ -239,21 +248,21 @@ * vt fb startup needs to be reworked. */ #define PHYS_IN_DMAP(pa) (dmaplimit == 0 || (pa) < dmaplimit) -#define VIRT_IN_DMAP(va) ((va) >= DMAP_MIN_ADDRESS && \ - (va) < (DMAP_MIN_ADDRESS + dmaplimit)) +#define VIRT_IN_DMAP(va) \ + ((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_low + dmaplimit) #define PMAP_HAS_DMAP 1 -#define PHYS_TO_DMAP(x) ({ \ +#define PHYS_TO_DMAP(x) __extension__ ({ \ KASSERT(PHYS_IN_DMAP(x), \ ("physical address %#jx not covered by the DMAP", \ (uintmax_t)x)); \ - (x) | DMAP_MIN_ADDRESS; }) + (x) + kva_layout.dmap_low; }) -#define DMAP_TO_PHYS(x) ({ \ +#define DMAP_TO_PHYS(x) __extension__ ({ \ KASSERT(VIRT_IN_DMAP(x), \ ("virtual address %#jx not covered by the DMAP", \ (uintmax_t)x)); \ - (x) & ~DMAP_MIN_ADDRESS; }) + (x) - kva_layout.dmap_low; }) /* * amd64 maps the page array into KVA so that it can be more easily @@ -274,7 +283,7 @@ */ #ifndef VM_KMEM_SIZE_MAX #define VM_KMEM_SIZE_MAX ((VM_MAX_KERNEL_ADDRESS - \ - VM_MIN_KERNEL_ADDRESS + 1) * 3 / 5) + kva_layout.km_low + 1) * 3 / 5) #endif /* initial pagein size of beginning of executable file */ diff --git a/sys/amd64/pt/pt.c b/sys/amd64/pt/pt.c new file mode 100644 index 000000000000..c7b75767680a --- /dev/null +++ b/sys/amd64/pt/pt.c @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2025 Bojan Novković <bnovkov@freebsd.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * hwt(4) Intel Processor Trace (PT) backend + * + * Driver Design Overview + * + * - Since PT is configured on a per-core basis, the driver uses + * 'smp_rendezvous' to start and disable tracing on each target core. + * - PT-specific resources are stored in a 'struct pt_ctx' context structure for + * each traced CPU core or thread. Upon initialization, a ToPA configuration + * is generated for each 'pt_ctx' structure using the HWT tracing buffers. + * The HWT tracing buffer is split into 4K ToPA entries. Currently, each + * 4K ToPA entry is configured to trigger an interrupt after it is filled. + * - The PT driver uses the XSAVE/XRSTOR PT extensions to load and save all + * relevant PT registers. Every time a traced thread is switched + * out or in, its state will be saved to or loaded from its corresponding + * 'pt_ctx' context. + * - When tracing starts, the PT hardware will start writing data into the + * tracing buffer. When a TOPA_INT entry is filled, it will trigger an + * interrupt before continuing. The interrupt handler will then fetch the + * last valid tracing buffer offset and enqueue a HWT_RECORD_BUFFER record. + * The driver is currently configured to use the NMI interrupt line. + * - The userspace PT backend waits for incoming HWT_RECORD_BUFFER records + * and uses the offsets to decode data from the tracing buffer. + * + * Future improvements and limitations + * + * - We currently configure the PT hardware to trigger an interrupt whenever + * a 4K ToPA entry is filled. While this is fine when tracing smaller + * functions or infrequent code paths, this will generate too much interrupt + * traffic when tracing hotter functions. A proper solution for this issue + * should estimate the amount of data generated by the current configuration + * and use it to determine interrupt frequency. + * + * - Support for more tracing options and PT features. + * + */ + +#include <sys/systm.h> +#include <sys/hwt.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/sdt.h> +#include <sys/smp.h> +#include <sys/taskqueue.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> + +#include <machine/atomic.h> +#include <machine/cpufunc.h> +#include <machine/fpu.h> +#include <machine/smp.h> +#include <machine/specialreg.h> + +#include <x86/apicvar.h> +#include <x86/x86_var.h> + +#include <dev/hwt/hwt_context.h> +#include <dev/hwt/hwt_vm.h> +#include <dev/hwt/hwt_backend.h> +#include <dev/hwt/hwt_config.h> +#include <dev/hwt/hwt_cpu.h> +#include <dev/hwt/hwt_record.h> +#include <dev/hwt/hwt_thread.h> + +#include <amd64/pt/pt.h> + +#ifdef PT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif +#define PT_SUPPORTED_FLAGS \ + (RTIT_CTL_MTCEN | RTIT_CTL_CR3FILTER | RTIT_CTL_DIS_TNT | \ + RTIT_CTL_USER | RTIT_CTL_OS | RTIT_CTL_BRANCHEN) +#define PT_XSAVE_MASK (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE) +#define PT_XSTATE_BV (PT_XSAVE_MASK | XFEATURE_ENABLED_PT) +#define PT_MAX_IP_RANGES 2 + +#define PT_TOPA_MASK_PTRS 0x7f +#define PT_TOPA_PAGE_MASK 0xffffff80 +#define PT_TOPA_PAGE_SHIFT 7 + +#define CPUID_PT_LEAF 0x14 + +MALLOC_DEFINE(M_PT, "pt", "Intel Processor Trace"); + +SDT_PROVIDER_DEFINE(pt); +SDT_PROBE_DEFINE(pt, , , topa__intr); + +TASKQUEUE_FAST_DEFINE_THREAD(pt); + +static void pt_send_buffer_record(void *arg, int pending __unused); +static int pt_topa_intr(struct trapframe *tf); + +/* + * Intel Processor Trace XSAVE-managed state. + */ +struct pt_ext_area { + uint64_t rtit_ctl; + uint64_t rtit_output_base; + uint64_t rtit_output_mask_ptrs; + uint64_t rtit_status; + uint64_t rtit_cr3_match; + uint64_t rtit_addr0_a; + uint64_t rtit_addr0_b; + uint64_t rtit_addr1_a; + uint64_t rtit_addr1_b; +}; + +struct pt_buffer { + uint64_t *topa_hw; /* ToPA table entries. */ + size_t size; + struct mtx lock; /* Lock for fields below. */ + vm_offset_t offset; + uint64_t wrap_count; + int curpage; +}; + +struct pt_ctx { + int id; + struct pt_buffer buf; /* ToPA buffer metadata */ + struct task task; /* ToPA buffer notification task */ + struct hwt_context *hwt_ctx; + uint8_t *save_area; /* PT XSAVE area */ +}; +/* PT tracing contexts used for CPU mode. */ +static struct pt_ctx *pt_pcpu_ctx; + +enum pt_cpu_state { + PT_DISABLED = 0, + PT_STOPPED, + PT_ACTIVE +}; + +static struct pt_cpu { + struct pt_ctx *ctx; /* active PT tracing context */ + enum pt_cpu_state state; /* used as part of trace stop protocol */ +} *pt_pcpu; + +/* + * PT-related CPUID bits. + */ +static struct pt_cpu_info { + uint32_t l0_eax; + uint32_t l0_ebx; + uint32_t l0_ecx; + uint32_t l1_eax; + uint32_t l1_ebx; + size_t xsave_area_size; + size_t xstate_hdr_offset; + size_t pt_xsave_offset; +} pt_info __read_mostly; + +static bool initialized = false; +static int cpu_mode_ctr = 0; + +static __inline enum pt_cpu_state +pt_cpu_get_state(int cpu_id) +{ + return (atomic_load_int(&pt_pcpu[cpu_id].state)); +} + +static __inline void +pt_cpu_set_state(int cpu_id, enum pt_cpu_state state) +{ + atomic_store_int(&pt_pcpu[cpu_id].state, state); +} + +static __inline struct xstate_hdr * +pt_ctx_get_xstate_hdr(struct pt_ctx *ctx) +{ + return ((struct xstate_hdr *)(ctx->save_area + + pt_info.xstate_hdr_offset)); +} + + +static __inline struct pt_ext_area * +pt_ctx_get_ext_area(struct pt_ctx *ctx) +{ + return ((struct pt_ext_area *)(ctx->save_area + + pt_info.pt_xsave_offset)); +} + +/* + * Updates current trace buffer offset from the + * ToPA MSRs. Records if the trace buffer wrapped. + */ +static __inline void +pt_update_buffer(struct pt_buffer *buf) +{ + uint64_t reg; + int curpage; + + /* Update buffer offset. */ + reg = rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS); + curpage = (reg & PT_TOPA_PAGE_MASK) >> PT_TOPA_PAGE_SHIFT; + mtx_lock_spin(&buf->lock); + /* Check if the output wrapped. */ + if (buf->curpage > curpage) + buf->wrap_count++; + buf->curpage = curpage; + buf->offset = reg >> 32; + mtx_unlock_spin(&buf->lock); + + dprintf("%s: wrap_cnt: %lu, curpage: %d, offset: %zu\n", __func__, + buf->wrap_count, buf->curpage, buf->offset); +} + +static __inline void +pt_fill_buffer_record(int id, struct pt_buffer *buf, + struct hwt_record_entry *rec) +{ + rec->record_type = HWT_RECORD_BUFFER; + rec->buf_id = id; + rec->curpage = buf->curpage; + rec->offset = buf->offset + (buf->wrap_count * buf->size); +} + +/* + * Enables or disables tracing on curcpu + * using the XSAVE/XRSTOR PT extensions. + */ +static void +pt_cpu_toggle_local(uint8_t *save_area, bool enable) +{ + u_long xcr0, cr0; + u_long xss; + + cr0 = rcr0(); + if (cr0 & CR0_TS) + clts(); + xcr0 = rxcr(XCR0); + if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK) + load_xcr(XCR0, xcr0 | PT_XSAVE_MASK); + xss = rdmsr(MSR_IA32_XSS); + wrmsr(MSR_IA32_XSS, xss | XFEATURE_ENABLED_PT); + + if (!enable) { + KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) != 0, + ("%s: PT is disabled", __func__)); + xsaves(save_area, XFEATURE_ENABLED_PT); + } else { + KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) == 0, + ("%s: PT is enabled", __func__)); + xrstors(save_area, XFEATURE_ENABLED_PT); + } + wrmsr(MSR_IA32_XSS, xss); + if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK) + load_xcr(XCR0, xcr0); + if (cr0 & CR0_TS) + load_cr0(cr0); +} + +/* + * Starts PT tracing on 'curcpu'. + */ +static void +pt_cpu_start(void *dummy) +{ + struct pt_cpu *cpu; + + cpu = &pt_pcpu[curcpu]; + MPASS(cpu->ctx != NULL); + + dprintf("%s: curcpu %d\n", __func__, curcpu); + load_cr4(rcr4() | CR4_XSAVE); + wrmsr(MSR_IA32_RTIT_STATUS, 0); + pt_cpu_set_state(curcpu, PT_ACTIVE); + pt_cpu_toggle_local(cpu->ctx->save_area, true); +} + +/* + * Stops PT tracing on 'curcpu'. + * Updates trace buffer offset to ensure + * any data generated between the last interrupt + * and the trace stop gets picked up by userspace. + */ +static void +pt_cpu_stop(void *dummy) +{ + struct pt_cpu *cpu; + struct pt_ctx *ctx; + + /* Shutdown may occur before PT gets properly configured. */ + if (pt_cpu_get_state(curcpu) == PT_DISABLED) + return; + + cpu = &pt_pcpu[curcpu]; + ctx = cpu->ctx; + MPASS(ctx != NULL); + dprintf("%s: curcpu %d\n", __func__, curcpu); + + pt_cpu_set_state(curcpu, PT_STOPPED); + pt_cpu_toggle_local(cpu->ctx->save_area, false); + pt_update_buffer(&ctx->buf); +} + +/* + * Prepares the Table of Physical Addresses (ToPA) metadata for 'pt_ctx'. + * The HWT trace buffer is split into 4K ToPA table entries and used + * as a circular buffer, meaning that the last ToPA entry points to + * the first ToPA entry. Each entry is configured to raise an + * interrupt after being filled. + */ +static int +pt_topa_prepare(struct pt_ctx *ctx, struct hwt_vm *vm) +{ + struct pt_buffer *buf; + size_t topa_size; + int i; + + topa_size = TOPA_SIZE_4K; + buf = &ctx->buf; + + KASSERT(buf->topa_hw == NULL, + ("%s: ToPA info already exists", __func__)); + buf->topa_hw = mallocarray(vm->npages + 1, sizeof(uint64_t), M_PT, + M_ZERO | M_WAITOK); + dprintf("%s: ToPA virt addr %p\n", __func__, buf->topa_hw); + buf->size = vm->npages * PAGE_SIZE; + for (i = 0; i < vm->npages; i++) { + buf->topa_hw[i] = VM_PAGE_TO_PHYS(vm->pages[i]) | topa_size; + /* + * XXX: TOPA_INT should ideally be set according to + * expected amount of incoming trace data. Too few TOPA_INT + * entries will not trigger interrupts often enough when tracing + * smaller functions. + */ + buf->topa_hw[i] |= TOPA_INT; + } + buf->topa_hw[vm->npages] = (uint64_t)vtophys(buf->topa_hw) | TOPA_END; + + return (0); +} + +/* + * Configures IP filtering for trace generation. + * A maximum of 2 ranges can be specified due to + * limitations imposed by the XSAVE/XRSTOR PT extensions. + */ +static int +pt_configure_ranges(struct pt_ctx *ctx, struct pt_cpu_config *cfg) +{ + struct pt_ext_area *pt_ext; + int nranges_supp, n, error = 0; + + pt_ext = pt_ctx_get_ext_area(ctx); + if (pt_info.l0_ebx & CPUPT_IPF) { + nranges_supp = (pt_info.l1_eax & CPUPT_NADDR_M) >> + CPUPT_NADDR_S; + + if (nranges_supp > PT_IP_FILTER_MAX_RANGES) + nranges_supp = PT_IP_FILTER_MAX_RANGES; + n = cfg->nranges; + if (n > nranges_supp) { + printf("%s: %d IP filtering ranges requested, CPU " + "supports %d, truncating\n", + __func__, n, nranges_supp); + n = nranges_supp; + } + + switch (n) { + case 2: + pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(1)); + pt_ext->rtit_addr1_a = cfg->ip_ranges[1].start; + pt_ext->rtit_addr1_b = cfg->ip_ranges[1].end; + case 1: + pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(0)); + pt_ext->rtit_addr0_a = cfg->ip_ranges[0].start; + pt_ext->rtit_addr0_b = cfg->ip_ranges[0].end; + break; + default: + error = (EINVAL); + break; + }; + } else + error = (ENXIO); + + return (error); +} + +static int +pt_init_ctx(struct pt_ctx *pt_ctx, struct hwt_vm *vm, int ctx_id) +{ + + dprintf("%s: ctx id %d\n", __func__, ctx_id); + + KASSERT(pt_ctx->buf.topa_hw == NULL, + ("%s: active ToPA buffer in context %p\n", __func__, pt_ctx)); + + memset(pt_ctx, 0, sizeof(struct pt_ctx)); + mtx_init(&pt_ctx->buf.lock, "pttopa", NULL, MTX_SPIN); + pt_ctx->save_area = malloc_aligned(pt_info.xsave_area_size, 64, + M_PT, M_NOWAIT | M_ZERO); + if (pt_ctx->save_area == NULL) + return (ENOMEM); + dprintf("%s: preparing ToPA buffer\n", __func__); + if (pt_topa_prepare(pt_ctx, vm) != 0) { + dprintf("%s: failed to prepare ToPA buffer\n", __func__); + free(pt_ctx->save_area, M_PT); + return (ENOMEM); + } + + pt_ctx->id = ctx_id; + TASK_INIT(&pt_ctx->task, 0, pt_send_buffer_record, pt_ctx); + + return (0); +} + +static void +pt_deinit_ctx(struct pt_ctx *pt_ctx) +{ + + if (pt_ctx->buf.topa_hw != NULL) + free(pt_ctx->buf.topa_hw, M_PT); + if (pt_ctx->save_area != NULL) + free(pt_ctx->save_area, M_PT); + memset(pt_ctx, 0, sizeof(*pt_ctx)); + pt_ctx->buf.topa_hw = NULL; +} + +/* + * HWT backend configuration method. + * + * Checks and translates the user-defined configuration to a + * set of PT tracing features. Uses the feature set to initialize + * the tracing context for the target CPU or thread. + */ +static int +pt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id) +{ + struct hwt_cpu *hwt_cpu; + struct hwt_thread *thr; + struct pt_ctx *pt_ctx; + struct pt_cpu_config *cfg; + struct pt_ext_area *pt_ext; + struct xstate_hdr *hdr; + int error; + + dprintf("%s\n", __func__); + + cfg = (struct pt_cpu_config *)ctx->config; + pt_ctx = NULL; + + /* Clear any flags we don't support yet. */ + cfg->rtit_ctl &= PT_SUPPORTED_FLAGS; + if (cfg->rtit_ctl & RTIT_CTL_MTCEN) { + if ((pt_info.l0_ebx & CPUPT_MTC) == 0) { + printf("%s: CPU does not support generating MTC " + "packets\n", __func__); + return (ENXIO); + } + } + + if (cfg->rtit_ctl & RTIT_CTL_CR3FILTER) { + if ((pt_info.l0_ebx & CPUPT_CR3) == 0) { + printf("%s: CPU does not support CR3 filtering\n", + __func__); + return (ENXIO); + } + } + + if (cfg->rtit_ctl & RTIT_CTL_DIS_TNT) { + if ((pt_info.l0_ebx & CPUPT_DIS_TNT) == 0) { + printf("%s: CPU does not support TNT\n", __func__); + return (ENXIO); + } + } + /* TODO: support for more config bits. */ + + if (ctx->mode == HWT_MODE_CPU) { + TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) { + if (hwt_cpu->cpu_id != cpu_id) + continue; + pt_ctx = &pt_pcpu_ctx[cpu_id]; + break; + } + } else { + TAILQ_FOREACH(thr, &ctx->threads, next) { + if (thr->thread_id != thread_id) + continue; + KASSERT(thr->private != NULL, + ("%s: hwt thread private" + " not set, thr %p", + __func__, thr)); + pt_ctx = (struct pt_ctx *)thr->private; + break; + } + } + if (pt_ctx == NULL) + return (ENOENT); + + dprintf("%s: preparing MSRs\n", __func__); + pt_ext = pt_ctx_get_ext_area(pt_ctx); + hdr = pt_ctx_get_xstate_hdr(pt_ctx); + + pt_ext->rtit_ctl |= cfg->rtit_ctl; + if (cfg->nranges != 0) { + dprintf("%s: preparing IPF ranges\n", __func__); + if ((error = pt_configure_ranges(pt_ctx, cfg)) != 0) + return (error); + } + pt_ctx->hwt_ctx = ctx; + pt_ext->rtit_ctl |= RTIT_CTL_TOPA; + pt_ext->rtit_output_base = (uint64_t)vtophys(pt_ctx->buf.topa_hw); + pt_ext->rtit_output_mask_ptrs = PT_TOPA_MASK_PTRS; + hdr->xstate_bv = XFEATURE_ENABLED_PT; + hdr->xstate_xcomp_bv = XFEATURE_ENABLED_PT | + XSTATE_XCOMP_BV_COMPACT; + pt_ext->rtit_ctl |= RTIT_CTL_TRACEEN; + pt_pcpu[cpu_id].ctx = pt_ctx; + pt_cpu_set_state(cpu_id, PT_STOPPED); + + return (0); +} + +/* + * hwt backend trace start operation. CPU affine. + */ +static void +pt_backend_enable(struct hwt_context *ctx, int cpu_id) +{ + if (ctx->mode == HWT_MODE_CPU) + return; + + KASSERT(curcpu == cpu_id, + ("%s: attempting to start PT on another cpu", __func__)); + pt_cpu_start(NULL); + CPU_SET(cpu_id, &ctx->cpu_map); +} + +/* + * hwt backend trace stop operation. CPU affine. + */ +static void +pt_backend_disable(struct hwt_context *ctx, int cpu_id) +{ + struct pt_cpu *cpu; + + if (ctx->mode == HWT_MODE_CPU) + return; + + KASSERT(curcpu == cpu_id, + ("%s: attempting to disable PT on another cpu", __func__)); + pt_cpu_stop(NULL); + CPU_CLR(cpu_id, &ctx->cpu_map); + cpu = &pt_pcpu[cpu_id]; + cpu->ctx = NULL; +} + +/* + * hwt backend trace start operation for remote CPUs. + */ +static int +pt_backend_enable_smp(struct hwt_context *ctx) +{ + + dprintf("%s\n", __func__); + if (ctx->mode == HWT_MODE_CPU && + atomic_swap_32(&cpu_mode_ctr, 1) != 0) + return (-1); + + KASSERT(ctx->mode == HWT_MODE_CPU, + ("%s: should only be used for CPU mode", __func__)); + smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_start, NULL, NULL); + + return (0); +} + +/* + * hwt backend trace stop operation for remote CPUs. + */ +static int +pt_backend_disable_smp(struct hwt_context *ctx) +{ + + dprintf("%s\n", __func__); + if (ctx->mode == HWT_MODE_CPU && + atomic_swap_32(&cpu_mode_ctr, 0) == 0) + return (-1); + + if (CPU_EMPTY(&ctx->cpu_map)) { + dprintf("%s: empty cpu map\n", __func__); + return (-1); + } + smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_stop, NULL, NULL); + + return (0); +} + +/* + * HWT backend initialization method. + * + * Installs the ToPA interrupt handler and initializes + * the tracing contexts used for HWT_MODE_CPU. + */ +static int +pt_backend_init(struct hwt_context *ctx) +{ + struct hwt_cpu *hwt_cpu; + int error; + + dprintf("%s\n", __func__); + if (ctx->mode == HWT_MODE_CPU) { + TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) { + error = pt_init_ctx(&pt_pcpu_ctx[hwt_cpu->cpu_id], + hwt_cpu->vm, hwt_cpu->cpu_id); + if (error) + return (error); + } + } + + return (0); +} + +/* + * HWT backend teardown method. + * + * Removes the ToPA interrupt handler, stops tracing on all active CPUs, + * and releases all previously allocated ToPA metadata. + */ +static int +pt_backend_deinit(struct hwt_context *ctx) +{ + struct pt_ctx *pt_ctx; + struct hwt_thread *thr; + int cpu_id; + + dprintf("%s\n", __func__); + + pt_backend_disable_smp(ctx); + if (ctx->mode == HWT_MODE_THREAD) { + TAILQ_FOREACH(thr, &ctx->threads, next) { + KASSERT(thr->private != NULL, + ("%s: thr->private not set", __func__)); + pt_ctx = (struct pt_ctx *)thr->private; + pt_deinit_ctx(pt_ctx); + } + } else { + CPU_FOREACH(cpu_id) { + if (!CPU_ISSET(cpu_id, &ctx->cpu_map)) + continue; + if (pt_pcpu[cpu_id].ctx != NULL) { + KASSERT(pt_pcpu[cpu_id].ctx == + &pt_pcpu_ctx[cpu_id], + ("%s: CPU mode tracing with non-cpu mode PT" + "context active", + __func__)); + pt_pcpu[cpu_id].ctx = NULL; + } + pt_ctx = &pt_pcpu_ctx[cpu_id]; + pt_deinit_ctx(pt_ctx); + memset(&pt_pcpu[cpu_id], 0, sizeof(struct pt_cpu)); + } + } + + return (0); +} + +/* + * Fetches current offset into the tracing buffer. + */ +static int +pt_backend_read(struct hwt_vm *vm, int *curpage, vm_offset_t *curpage_offset, + uint64_t *data) +{ + struct pt_buffer *buf; + + if (vm->ctx->mode == HWT_MODE_THREAD) + buf = &((struct pt_ctx *)vm->thr->private)->buf; + else + buf = &pt_pcpu[vm->cpu->cpu_id].ctx->buf; + mtx_lock_spin(&buf->lock); + *curpage = buf->curpage; + *curpage_offset = buf->offset + (buf->wrap_count * vm->ctx->bufsize); + mtx_unlock_spin(&buf->lock); + + return (0); +} + +/* + * HWT thread creation hook. + * Allocates and associates a 'struct pt_ctx' for a given hwt thread. + */ +static int +pt_backend_alloc_thread(struct hwt_thread *thr) +{ + struct pt_ctx *pt_ctx; + int error; + + /* Omit M_WAITOK since this might get invoked a non-sleepable context */ + pt_ctx = malloc(sizeof(*pt_ctx), M_PT, M_NOWAIT | M_ZERO); + if (pt_ctx == NULL) + return (ENOMEM); + + error = pt_init_ctx(pt_ctx, thr->vm, thr->thread_id); + if (error) + return (error); + + thr->private = pt_ctx; + return (0); +} +/* + * HWT thread teardown hook. + */ +static void +pt_backend_free_thread(struct hwt_thread *thr) +{ + struct pt_ctx *ctx; + + ctx = (struct pt_ctx *)thr->private; + + pt_deinit_ctx(ctx); + free(ctx, M_PT); +} + +static void +pt_backend_dump(int cpu_id) +{ +} + +static struct hwt_backend_ops pt_ops = { + .hwt_backend_init = pt_backend_init, + .hwt_backend_deinit = pt_backend_deinit, + + .hwt_backend_configure = pt_backend_configure, + + .hwt_backend_enable = pt_backend_enable, + .hwt_backend_disable = pt_backend_disable, + +#ifdef SMP + .hwt_backend_enable_smp = pt_backend_enable_smp, + .hwt_backend_disable_smp = pt_backend_disable_smp, +#endif + + .hwt_backend_read = pt_backend_read, + .hwt_backend_dump = pt_backend_dump, + + .hwt_backend_thread_alloc = pt_backend_alloc_thread, + .hwt_backend_thread_free = pt_backend_free_thread, +}; + +static struct hwt_backend backend = { + .ops = &pt_ops, + .name = "pt", + .kva_req = 1, +}; + +/* + * Reads the latest valid trace buffer offset and enqueues + * a HWT_RECORD_BUFFER record. + * Used as a taskqueue routine from the ToPA interrupt handler. + */ +static void +pt_send_buffer_record(void *arg, int pending __unused) +{ + struct hwt_record_entry record; + struct pt_ctx *ctx = (struct pt_ctx *)arg; + + /* Prepare buffer record. */ + mtx_lock_spin(&ctx->buf.lock); + pt_fill_buffer_record(ctx->id, &ctx->buf, &record); + mtx_unlock_spin(&ctx->buf.lock); + hwt_record_ctx(ctx->hwt_ctx, &record, M_ZERO | M_NOWAIT); +} +static void +pt_topa_status_clear(void) +{ + uint64_t reg; + + reg = rdmsr(MSR_IA_GLOBAL_STATUS_RESET); + reg &= ~GLOBAL_STATUS_FLAG_TRACETOPAPMI; + reg |= GLOBAL_STATUS_FLAG_TRACETOPAPMI; + wrmsr(MSR_IA_GLOBAL_STATUS_RESET, reg); +} + +/* + * ToPA PMI handler. + * + * Invoked every time a ToPA entry marked with TOPA_INT is filled. + * Uses taskqueue to enqueue a buffer record for userspace. + * Re-enables the PC interrupt line as long as tracing is active. + */ +static int +pt_topa_intr(struct trapframe *tf) +{ + struct pt_buffer *buf; + struct pt_ctx *ctx; + uint64_t reg; + + SDT_PROBE0(pt, , , topa__intr); + + if (pt_cpu_get_state(curcpu) != PT_ACTIVE) { + return (0); + } + reg = rdmsr(MSR_IA_GLOBAL_STATUS); + if ((reg & GLOBAL_STATUS_FLAG_TRACETOPAPMI) == 0) { + /* ACK spurious or leftover interrupt. */ + pt_topa_status_clear(); + return (1); + } + + ctx = pt_pcpu[curcpu].ctx; + buf = &ctx->buf; + KASSERT(buf->topa_hw != NULL, + ("%s: ToPA PMI interrupt with invalid buffer", __func__)); + + pt_cpu_toggle_local(ctx->save_area, false); + pt_update_buffer(buf); + pt_topa_status_clear(); + taskqueue_enqueue_flags(taskqueue_pt, &ctx->task, + TASKQUEUE_FAIL_IF_PENDING); + + if (pt_cpu_get_state(curcpu) == PT_ACTIVE) { + pt_cpu_toggle_local(ctx->save_area, true); + lapic_reenable_pcint(); + } + return (1); +} + +/* + * Module initialization. + * + * Saves all PT-related cpuid info, registers itself as a HWT backend, + * and allocates metadata required to keep track of tracing operations + * on each CPU. + */ +static int +pt_init(void) +{ + u_int cp[4]; + int error; + + dprintf("pt: Enumerating part 1\n"); + cpuid_count(CPUID_PT_LEAF, 0, cp); + dprintf("pt: Maximum valid sub-leaf Index: %x\n", cp[0]); + dprintf("pt: ebx %x\n", cp[1]); + dprintf("pt: ecx %x\n", cp[2]); + + pt_info.l0_eax = cp[0]; + pt_info.l0_ebx = cp[1]; + pt_info.l0_ecx = cp[2]; + + dprintf("pt: Enumerating part 2\n"); + cpuid_count(CPUID_PT_LEAF, 1, cp); + dprintf("pt: eax %x\n", cp[0]); + dprintf("pt: ebx %x\n", cp[1]); + + pt_info.l1_eax = cp[0]; + pt_info.l1_ebx = cp[1]; + + error = hwt_backend_register(&backend); + if (error != 0) { + printf("pt: unable to register hwt backend, error %d\n", error); + return (error); + } + pt_pcpu = mallocarray(mp_ncpus, sizeof(struct pt_cpu), M_PT, + M_ZERO | M_WAITOK); + pt_pcpu_ctx = mallocarray(mp_ncpus, sizeof(struct pt_ctx), M_PT, + M_ZERO | M_WAITOK); + + nmi_register_handler(pt_topa_intr); + if (!lapic_enable_pcint()) { + nmi_remove_handler(pt_topa_intr); + hwt_backend_unregister(&backend); + free(pt_pcpu, M_PT); + free(pt_pcpu_ctx, M_PT); + pt_pcpu = NULL; + pt_pcpu_ctx = NULL; + printf("pt: failed to setup interrupt line\n"); + return (error); + } + initialized = true; + + return (0); +} + +/* + * Checks whether the CPU support Intel PT and + * initializes XSAVE area info. + * + * The driver relies on XSAVE/XRSTOR PT extensions, + * Table of Physical Addresses (ToPA) support, and + * support for multiple ToPA entries. + */ +static bool +pt_supported(void) +{ + u_int cp[4]; + + if ((cpu_stdext_feature & CPUID_STDEXT_PROCTRACE) == 0) { + printf("pt: CPU does not support Intel Processor Trace\n"); + return (false); + } + if ((cpu_feature2 & CPUID2_XSAVE) == 0) { + printf("pt: XSAVE is not supported\n"); + return (false); + } + if (!xsave_extfeature_supported(XFEATURE_ENABLED_PT, true)) { + printf("pt: CPU does not support managing PT state using XSAVE\n"); + return (false); + } + if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVEC)) { + printf("pt: XSAVE compaction is not supported\n"); + return (false); + } + if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVES)) { + printf("pt: CPU does not support XSAVES/XRSTORS\n"); + return (false); + } + + /* Require ToPA support. */ + cpuid_count(CPUID_PT_LEAF, 0, cp); + if ((cp[2] & CPUPT_TOPA) == 0) { + printf("pt: ToPA is not supported\n"); + return (false); + } + if ((cp[2] & CPUPT_TOPA_MULTI) == 0) { + printf("pt: multiple ToPA outputs are not supported\n"); + return (false); + } + + pt_info.xstate_hdr_offset = xsave_area_hdr_offset(); + pt_info.xsave_area_size = xsave_area_size(PT_XSTATE_BV, true, true); + pt_info.pt_xsave_offset = xsave_area_offset(PT_XSTATE_BV, + XFEATURE_ENABLED_PT, true, true); + + return (true); +} + +static void +pt_deinit(void) +{ + if (!initialized) + return; + nmi_remove_handler(pt_topa_intr); + lapic_disable_pcint(); + hwt_backend_unregister(&backend); + free(pt_pcpu, M_PT); + free(pt_pcpu_ctx, M_PT); + pt_pcpu = NULL; + initialized = false; +} + +static int +pt_modevent(module_t mod, int type, void *data) +{ + switch (type) { + case MOD_LOAD: + if (!pt_supported() || pt_init() != 0) { + return (ENXIO); + } + break; + case MOD_UNLOAD: + pt_deinit(); + break; + default: + break; + } + + return (0); +} + +static moduledata_t pt_mod = { "intel_pt", pt_modevent, NULL }; + +DECLARE_MODULE(intel_pt, pt_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_DEPEND(intel_pt, hwt, 1, 1, 1); +MODULE_VERSION(intel_pt, 1); diff --git a/sys/dev/sound/midi/sequencer.h b/sys/amd64/pt/pt.h index 22ea0ae6c1b6..2423afdf22e9 100644 --- a/sys/dev/sound/midi/sequencer.h +++ b/sys/amd64/pt/pt.h @@ -1,9 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2003 Mathew Kanner - * Copyright (c) 1999 Seigo Tanimura - * All rights reserved. + * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,63 +25,25 @@ * SUCH DAMAGE. */ -/* - * Include file for the midi sequence driver. - */ - -#ifndef _SEQUENCER_H_ -#define _SEQUENCER_H_ - -#define NSEQ_MAX 16 - -/* - * many variables should be reduced to a range. Here define a macro - */ - -#define RANGE(var, low, high) (var) = \ -((var)<(low)?(low) : (var)>(high)?(high) : (var)) - -#ifdef _KERNEL - -void seq_timer(void *arg); +#ifndef _AMD64_PT_PT_H_ +#define _AMD64_PT_PT_H_ -SYSCTL_DECL(_hw_midi_seq); +#include <sys/types.h> -extern int seq_debug; +#include <x86/include/specialreg.h> -#define SEQ_DEBUG(y, x) \ - do { \ - if (seq_debug >= y) { \ - (x); \ - } \ - } while (0) +#define PT_IP_FILTER_MAX_RANGES (2) /* Intel SDM Vol. 3C, 33-29 */ -SYSCTL_DECL(_hw_midi); - -#endif /* _KERNEL */ - -#define SYNTHPROP_MIDI 1 -#define SYNTHPROP_SYNTH 2 -#define SYNTHPROP_RX 4 -#define SYNTHPROP_TX 8 - -struct _midi_cmdtab { - int cmd; - char *name; +struct pt_cpu_config { + uint64_t rtit_ctl; + register_t cr3_filter; + int nranges; + struct ipf_range { + vm_offset_t start; + vm_offset_t end; + } ip_ranges[PT_IP_FILTER_MAX_RANGES]; + uint32_t mtc_freq; + uint32_t cyc_thresh; + uint32_t psb_freq; }; -typedef struct _midi_cmdtab midi_cmdtab; -extern midi_cmdtab cmdtab_seqevent[]; -extern midi_cmdtab cmdtab_seqioctl[]; -extern midi_cmdtab cmdtab_timer[]; -extern midi_cmdtab cmdtab_seqcv[]; -extern midi_cmdtab cmdtab_seqccmn[]; - -char *midi_cmdname(int cmd, midi_cmdtab * tab); - -enum { - MORE, - TIMERARMED, - QUEUEFULL -}; - -#endif +#endif /* !_AMD64_PT_PT_H_ */ diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c index 92eb0589f80b..78883296c5b7 100644 --- a/sys/arm/arm/pmap-v6.c +++ b/sys/arm/arm/pmap-v6.c @@ -5767,7 +5767,7 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) CTR5(KTR_PMAP, "%s: page %p - 0x%08X oma: %d, ma: %d", __func__, m, VM_PAGE_TO_PHYS(m), oma, ma); - if ((m->flags & PG_FICTITIOUS) != 0) + if (ma == oma || (m->flags & PG_FICTITIOUS) != 0) return; #if 0 /* @@ -5784,22 +5784,20 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) * If page is not mapped by sf buffer, map the page * transient and do invalidation. */ - if (ma != oma) { - pa = VM_PAGE_TO_PHYS(m); - sched_pin(); - pc = get_pcpu(); - cmap2_pte2p = pc->pc_cmap2_pte2p; - mtx_lock(&pc->pc_cmap_lock); - if (pte2_load(cmap2_pte2p) != 0) - panic("%s: CMAP2 busy", __func__); - pte2_store(cmap2_pte2p, PTE2_KERN_NG(pa, PTE2_AP_KRW, - vm_memattr_to_pte2(ma))); - dcache_wbinv_poc((vm_offset_t)pc->pc_cmap2_addr, pa, PAGE_SIZE); - pte2_clear(cmap2_pte2p); - tlb_flush((vm_offset_t)pc->pc_cmap2_addr); - sched_unpin(); - mtx_unlock(&pc->pc_cmap_lock); - } + pa = VM_PAGE_TO_PHYS(m); + sched_pin(); + pc = get_pcpu(); + cmap2_pte2p = pc->pc_cmap2_pte2p; + mtx_lock(&pc->pc_cmap_lock); + if (pte2_load(cmap2_pte2p) != 0) + panic("%s: CMAP2 busy", __func__); + pte2_store(cmap2_pte2p, PTE2_KERN_NG(pa, PTE2_AP_KRW, + vm_memattr_to_pte2(ma))); + dcache_wbinv_poc((vm_offset_t)pc->pc_cmap2_addr, pa, PAGE_SIZE); + pte2_clear(cmap2_pte2p); + tlb_flush((vm_offset_t)pc->pc_cmap2_addr); + sched_unpin(); + mtx_unlock(&pc->pc_cmap_lock); } /* diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index d2e56a270f54..a09da794e77d 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -497,7 +497,8 @@ static bool pmap_pv_insert_l3c(pmap_t pmap, vm_offset_t va, vm_page_t m, struct rwlock **lockp); static void pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va); static int pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, - pd_entry_t l1e, struct spglist *free, struct rwlock **lockp); + pd_entry_t l1e, bool demote_kl2e, struct spglist *free, + struct rwlock **lockp); static int pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t sva, pd_entry_t l2e, struct spglist *free, struct rwlock **lockp); static bool pmap_remove_l3c(pmap_t pmap, pt_entry_t *l3p, vm_offset_t va, @@ -3847,8 +3848,7 @@ pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va) PMAP_LOCK_ASSERT(pmap, MA_OWNED); ml3 = pmap_remove_pt_page(pmap, va); - if (ml3 == NULL) - panic("pmap_remove_kernel_l2: Missing pt page"); + KASSERT(ml3 != NULL, ("pmap_remove_kernel_l2: missing pt page")); ml3pa = VM_PAGE_TO_PHYS(ml3); newl2 = PHYS_TO_PTE(ml3pa) | L2_TABLE; @@ -3873,8 +3873,8 @@ pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va) * pmap_remove_l2: Do the things to unmap a level 2 superpage. */ static int -pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, - pd_entry_t l1e, struct spglist *free, struct rwlock **lockp) +pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, pd_entry_t l1e, + bool demote_kl2e, struct spglist *free, struct rwlock **lockp) { struct md_page *pvh; pt_entry_t old_l2; @@ -3910,9 +3910,7 @@ pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, vm_page_aflag_clear(mt, PGA_WRITEABLE); } } - if (pmap == kernel_pmap) { - pmap_remove_kernel_l2(pmap, l2, sva); - } else { + if (pmap != kernel_pmap) { ml3 = pmap_remove_pt_page(pmap, sva); if (ml3 != NULL) { KASSERT(vm_page_any_valid(ml3), @@ -3923,6 +3921,14 @@ pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, ml3->ref_count = 0; pmap_add_delayed_free_list(ml3, free, false); } + } else if (demote_kl2e) { + pmap_remove_kernel_l2(pmap, l2, sva); + } else { + ml3 = vm_radix_lookup(&pmap->pm_root, pmap_l2_pindex(sva)); + if (vm_page_any_valid(ml3)) { + ml3->valid = 0; + pmap_zero_page(ml3); + } } return (pmap_unuse_pt(pmap, sva, l1e, free)); } @@ -4232,7 +4238,7 @@ pmap_remove1(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, bool map_delete) if ((l3_paddr & ATTR_DESCR_MASK) == L2_BLOCK) { if (sva + L2_SIZE == va_next && eva >= va_next) { pmap_remove_l2(pmap, l2, sva, pmap_load(l1), - &free, &lock); + true, &free, &lock); continue; } else if (pmap_demote_l2_locked(pmap, l2, sva, &lock) == NULL) @@ -5747,33 +5753,51 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, } } SLIST_INIT(&free); - if ((old_l2 & ATTR_DESCR_MASK) == L2_BLOCK) + if ((old_l2 & ATTR_DESCR_MASK) == L2_BLOCK) { (void)pmap_remove_l2(pmap, l2, va, - pmap_load(pmap_l1(pmap, va)), &free, lockp); - else + pmap_load(pmap_l1(pmap, va)), false, &free, lockp); + } else { + if (ADDR_IS_KERNEL(va)) { + /* + * Try to save the ptp in the trie + * before any changes to mappings are + * made. Abort on failure. + */ + mt = PTE_TO_VM_PAGE(old_l2); + if (pmap_insert_pt_page(pmap, mt, false, + false)) { + CTR1(KTR_PMAP, + "pmap_enter_l2: cannot ins kern ptp va %#lx", + va); + return (KERN_RESOURCE_SHORTAGE); + } + /* + * Both pmap_remove_l2() and + * pmap_remove_l3_range() will zero fill + * the L3 kernel page table page. + */ + } pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE, &free, lockp); + if (ADDR_IS_KERNEL(va)) { + /* + * The TLB could have an intermediate + * entry for the L3 kernel page table + * page, so request an invalidation at + * all levels after clearing the + * L2_TABLE entry. + */ + pmap_clear(l2); + pmap_s1_invalidate_page(pmap, va, false); + } + } + KASSERT(pmap_load(l2) == 0, + ("pmap_enter_l2: non-zero L2 entry %p", l2)); if (!ADDR_IS_KERNEL(va)) { vm_page_free_pages_toq(&free, true); - KASSERT(pmap_load(l2) == 0, - ("pmap_enter_l2: non-zero L2 entry %p", l2)); } else { KASSERT(SLIST_EMPTY(&free), ("pmap_enter_l2: freed kernel page table page")); - - /* - * Both pmap_remove_l2() and pmap_remove_l3_range() - * will leave the kernel page table page zero filled. - * Nonetheless, the TLB could have an intermediate - * entry for the kernel page table page, so request - * an invalidation at all levels after clearing - * the L2_TABLE entry. - */ - mt = PTE_TO_VM_PAGE(pmap_load(l2)); - if (pmap_insert_pt_page(pmap, mt, false, false)) - panic("pmap_enter_l2: trie insert failed"); - pmap_clear(l2); - pmap_s1_invalidate_page(pmap, va, false); } } @@ -8045,6 +8069,8 @@ pmap_unmapbios(void *p, vm_size_t size) void pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) { + if (m->md.pv_memattr == ma) + return; m->md.pv_memattr = ma; @@ -8424,8 +8450,8 @@ pmap_demote_l2_abort(pmap_t pmap, vm_offset_t va, pt_entry_t *l2, struct spglist free; SLIST_INIT(&free); - (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), &free, - lockp); + (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), true, + &free, lockp); vm_page_free_pages_toq(&free, true); } diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index ae7cf14c8f8e..1facab47473c 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1359,10 +1359,7 @@ adaasync(void *callback_arg, uint32_t code, case AC_GETDEV_CHANGED: { softc = (struct ada_softc *)periph->softc; - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, periph->path); /* * Update our information based on the new Identify data. diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 833df6cfb99b..730656684e2a 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -767,27 +767,28 @@ camperiphfree(struct cam_periph *periph) CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n")); if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) { - union ccb ccb; - void *arg; - - memset(&ccb, 0, sizeof(ccb)); switch (periph->deferred_ac) { - case AC_FOUND_DEVICE: - ccb.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); - xpt_action(&ccb); - arg = &ccb; + case AC_FOUND_DEVICE: { + struct ccb_getdev cgd; + + xpt_gdev_type(&cgd, periph->path); + periph->deferred_callback(NULL, periph->deferred_ac, + periph->path, &cgd); break; - case AC_PATH_REGISTERED: - xpt_path_inq(&ccb.cpi, periph->path); - arg = &ccb; + } + case AC_PATH_REGISTERED: { + struct ccb_pathinq cpi; + + xpt_path_inq(&cpi, periph->path); + periph->deferred_callback(NULL, periph->deferred_ac, + periph->path, &cpi); break; + } default: - arg = NULL; + periph->deferred_callback(NULL, periph->deferred_ac, + periph->path, NULL); break; } - periph->deferred_callback(NULL, periph->deferred_ac, - periph->path, arg); } xpt_free_path(periph->path); free(periph, M_CAMPERIPH); @@ -1682,10 +1683,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig, /* * Grab the inquiry data for this device. */ - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, ccb->ccb_h.path); err_action = scsi_error_action(&ccb->csio, &cgd.inq_data, sense_flags); @@ -2133,11 +2131,7 @@ cam_periph_devctl_notify(union ccb *ccb) sbuf_cat(&sb, "serial=\""); if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) != NULL) { - xpt_setup_ccb(&cgd->ccb_h, ccb->ccb_h.path, - CAM_PRIORITY_NORMAL); - cgd->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)cgd); - + xpt_gdev_type(cgd, ccb->ccb_h.path); if (cgd->ccb_h.status == CAM_REQ_CMP) sbuf_bcat(&sb, cgd->serial_num, cgd->serial_num_len); xpt_free_ccb((union ccb *)cgd); diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 38bc82c69aad..2ec736e7f4ac 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -2471,15 +2471,12 @@ xptsetasyncfunc(struct cam_ed *device, void *arg) if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) return (1); - memset(&cgd, 0, sizeof(cgd)); xpt_compile_path(&path, NULL, device->target->bus->path_id, device->target->target_id, device->lun_id); - xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, &path); csa->callback(csa->callback_arg, AC_FOUND_DEVICE, &path, &cgd); diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h index 06ef52580120..efa6c823245a 100644 --- a/sys/cam/cam_xpt.h +++ b/sys/cam/cam_xpt.h @@ -145,19 +145,31 @@ uint32_t xpt_poll_setup(union ccb *start_ccb); void xpt_sim_poll(struct cam_sim *sim); /* - * Perform a path inquiry at the request priority. The bzero may be - * unnecessary. + * Perform a path inquiry. bzero may be redundant for allocated CCBs, but for + * the on-stack CCBs it's required. */ static inline void xpt_path_inq(struct ccb_pathinq *cpi, struct cam_path *path) { - bzero(cpi, sizeof(*cpi)); - xpt_setup_ccb(&cpi->ccb_h, path, CAM_PRIORITY_NORMAL); + xpt_setup_ccb(&cpi->ccb_h, path, CAM_PRIORITY_NONE); cpi->ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)cpi); } +/* + * Perform get device type. bzero may be redundant for allocated CCBs, but for + * the on-stack CCBs it's required. + */ +static inline void +xpt_gdev_type(struct ccb_getdev *cgd, struct cam_path *path) +{ + bzero(cgd, sizeof(*cgd)); + xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NONE); + cgd->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)cgd); +} + #endif /* _KERNEL */ #endif /* _CAM_CAM_XPT_H */ diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c index 9246f95a080e..7f8bf3516804 100644 --- a/sys/cam/mmc/mmc_da.c +++ b/sys/cam/mmc/mmc_da.c @@ -692,10 +692,7 @@ sddaasync(void *callback_arg, uint32_t code, case AC_GETDEV_CHANGED: { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_GETDEV_CHANGED\n")); - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, periph->path); cam_periph_async(periph, code, path, arg); break; } @@ -789,7 +786,8 @@ sddaregister(struct cam_periph *periph, void *arg) static int mmc_exec_app_cmd(struct cam_periph *periph, union ccb *ccb, - struct mmc_command *cmd) { + struct mmc_command *cmd) +{ int err; /* Send APP_CMD first */ @@ -843,7 +841,8 @@ mmc_exec_app_cmd(struct cam_periph *periph, union ccb *ccb, } static int -mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) { +mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) +{ int err; struct mmc_command cmd; struct mmc_data d; @@ -869,7 +868,8 @@ mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) { static int mmc_send_ext_csd(struct cam_periph *periph, union ccb *ccb, - uint8_t *rawextcsd, size_t buf_len) { + uint8_t *rawextcsd, size_t buf_len) +{ int err; struct mmc_data d; @@ -966,14 +966,16 @@ mmc_switch(struct cam_periph *periph, union ccb *ccb, } static uint32_t -mmc_get_spec_vers(struct cam_periph *periph) { +mmc_get_spec_vers(struct cam_periph *periph) +{ struct sdda_softc *softc = (struct sdda_softc *)periph->softc; return (softc->csd.spec_vers); } static uint64_t -mmc_get_media_size(struct cam_periph *periph) { +mmc_get_media_size(struct cam_periph *periph) +{ struct sdda_softc *softc = (struct sdda_softc *)periph->softc; return (softc->mediasize); @@ -992,7 +994,8 @@ mmc_get_cmd6_timeout(struct cam_periph *periph) static int mmc_sd_switch(struct cam_periph *periph, union ccb *ccb, uint8_t mode, uint8_t grp, uint8_t value, - uint8_t *res) { + uint8_t *res) +{ struct mmc_data mmc_d; uint32_t arg; int err; @@ -1069,7 +1072,8 @@ mmc_set_timing(struct cam_periph *periph, } static void -sdda_start_init_task(void *context, int pending) { +sdda_start_init_task(void *context, int pending) +{ union ccb *new_ccb; struct cam_periph *periph; @@ -1088,7 +1092,8 @@ sdda_start_init_task(void *context, int pending) { } static void -sdda_set_bus_width(struct cam_periph *periph, union ccb *ccb, int width) { +sdda_set_bus_width(struct cam_periph *periph, union ccb *ccb, int width) +{ struct sdda_softc *softc = (struct sdda_softc *)periph->softc; struct mmc_params *mmcp = &periph->path->device->mmc_ident_data; int err; @@ -1523,10 +1528,7 @@ sdda_add_part(struct cam_periph *periph, u_int type, const char *name, bioq_init(&part->bio_queue); - bzero(&cpi, sizeof(cpi)); - xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); + xpt_path_inq(&cpi, periph->path); /* * Register this media as a disk diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 13a376ebb6e3..b518f84454ad 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -3708,11 +3708,7 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio, /* * Get the device information. */ - xpt_setup_ccb(&cgd->ccb_h, - csio->ccb_h.path, - CAM_PRIORITY_NORMAL); - cgd->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)cgd); + xpt_gdev_type(cgd, csio->ccb_h.path); /* * If the device is unconfigured, just pretend that it is a hard @@ -5144,11 +5140,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, /* * Get the device information. */ - xpt_setup_ccb(&cgd->ccb_h, - csio->ccb_h.path, - CAM_PRIORITY_NORMAL); - cgd->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)cgd); + xpt_gdev_type(cgd, csio->ccb_h.path); /* * If the device is unconfigured, just pretend that it is a hard diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index 00a417f65052..e622a96ec77e 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -1240,13 +1240,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) /*getcount_only*/0); status = done_ccb->ccb_h.status; - - bzero(&cgd, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, - done_ccb->ccb_h.path, - CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, done_ccb->ccb_h.path); if (scsi_extract_sense_ccb(done_ccb, &error_code, &sense_key, &asc, &ascq)) diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c index 89a817c1b488..3da22ba61392 100644 --- a/sys/cam/scsi/scsi_ch.c +++ b/sys/cam/scsi/scsi_ch.c @@ -1705,11 +1705,7 @@ chscsiversion(struct cam_periph *periph) /* * Get the device information. */ - xpt_setup_ccb(&cgd->ccb_h, - periph->path, - CAM_PRIORITY_NORMAL); - cgd->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)cgd); + xpt_gdev_type(cgd, periph->path); if (cgd->ccb_h.status != CAM_REQ_CMP) { xpt_free_ccb((union ccb *)cgd); diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 0a2389cd9b5d..d02750aaacaf 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -5035,11 +5035,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb) /*timeout*/0, /*getcount_only*/0); - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path, - CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, done_ccb->ccb_h.path); if (scsi_extract_sense_ccb(done_ccb, &error_code, &sense_key, &asc, &ascq)) @@ -5077,6 +5073,18 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb) * behind a SATL translation that's fallen into a * terminally fatal state. * + * 4/2 happens on some HGST drives that are quite + * ill. We've already sent the start unit command (for + * which we ignore a 44/0 asc/ascq, which I'm hesitant + * to change since it's so basic and there's other error + * conditions to the START UNIT we should ignore). So to + * require initialization at this point when it should + * be fine implies to me, at least, that we should + * invalidate. Since we do read capacity in geom tasting + * a lot, and since this timeout is long, this leads to + * up to a 10 minute delay in booting. + * + * 4/2: LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED * 25/0: LOGICAL UNIT NOT SUPPORTED * 44/0: INTERNAL TARGET FAILURE * 44/1: PERSISTENT RESERVATION INFORMATION LOST @@ -5084,6 +5092,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb) */ if ((have_sense) && (asc != 0x25) && (asc != 0x44) + && (asc != 0x04 && ascq != 0x02) && (error_code == SSD_CURRENT_ERROR || error_code == SSD_DESC_CURRENT_ERROR)) { const char *sense_key_desc; diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index c429e820a1fd..435874a9874a 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -979,10 +979,7 @@ ses_paths_iter(enc_softc_t *enc, enc_element_t *elm, != CAM_REQ_CMP) return; - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, path); if (cam_ccb_success((union ccb *)&cgd)) callback(enc, elm, path, callback_arg); diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c index cfd48c98f30e..88147393192f 100644 --- a/sys/cam/scsi/scsi_sa.c +++ b/sys/cam/scsi/scsi_sa.c @@ -4731,12 +4731,7 @@ saextget(struct cdev *dev, struct cam_periph *periph, struct sbuf *sb, SASBADDVARSTR(sb, indent, periph->periph_name, %s, periph_name, strlen(periph->periph_name) + 1); SASBADDUINT(sb, indent, periph->unit_number, %u, unit_number); - memset(&cgd, 0, sizeof(cgd)); - xpt_setup_ccb(&cgd.ccb_h, - periph->path, - CAM_PRIORITY_NORMAL); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + xpt_gdev_type(&cgd, periph->path); if ((cgd.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { g->status = MT_EXT_GET_ERROR; snprintf(g->error_str, sizeof(g->error_str), diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c index 439dd2050a95..bef35243af98 100644 --- a/sys/cam/scsi/scsi_xpt.c +++ b/sys/cam/scsi/scsi_xpt.c @@ -1915,6 +1915,15 @@ typedef struct { int lunindex[0]; } scsi_scan_bus_info; +static void +free_scan_info(scsi_scan_bus_info *scan_info) +{ + KASSERT(scan_info->cpi != NULL, + ("scan_info (%p) missing its ccb_pathinq CCB\n", scan_info)); + xpt_free_ccb((union ccb *)scan_info->cpi); + free(scan_info, M_CAMXPT); +} + /* * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. * As the scan progresses, scsi_scan_bus is used as the @@ -1945,10 +1954,7 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb) xpt_done(request_ccb); return; } - xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, - request_ccb->ccb_h.pinfo.priority); - work_ccb->ccb_h.func_code = XPT_PATH_INQ; - xpt_action(work_ccb); + xpt_path_inq(&work_ccb->cpi, request_ccb->ccb_h.path); if (work_ccb->ccb_h.status != CAM_REQ_CMP) { request_ccb->ccb_h.status = work_ccb->ccb_h.status; xpt_free_ccb(work_ccb); @@ -2037,16 +2043,14 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb) printf( "scsi_scan_bus: xpt_create_path failed with status %#x, bus scan halted\n", status); - free(scan_info, M_CAMXPT); + free_scan_info(scan_info); request_ccb->ccb_h.status = status; - xpt_free_ccb(work_ccb); xpt_done(request_ccb); break; } work_ccb = xpt_alloc_ccb_nowait(); if (work_ccb == NULL) { - xpt_free_ccb((union ccb *)scan_info->cpi); - free(scan_info, M_CAMXPT); + free_scan_info(scan_info); xpt_free_path(path); request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(request_ccb); @@ -2179,16 +2183,16 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb) * Check to see if we scan any further luns. */ if (next_target) { - int done; + bool done; /* * Free the current request path- we're done with it. */ xpt_free_path(oldpath); hop_again: - done = 0; + done = false; if (scan_info->request_ccb->ccb_h.func_code == XPT_SCAN_TGT) { - done = 1; + done = true; } else if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { scan_info->counter++; if (scan_info->counter == @@ -2197,23 +2201,22 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb) } if (scan_info->counter >= scan_info->cpi->max_target+1) { - done = 1; + done = true; } } else { scan_info->counter--; if (scan_info->counter == 0) { - done = 1; + done = true; } } if (done) { mtx_unlock(mtx); xpt_free_ccb(request_ccb); - xpt_free_ccb((union ccb *)scan_info->cpi); request_ccb = scan_info->request_ccb; CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("SCAN done for %p\n", scan_info)); - free(scan_info, M_CAMXPT); + free_scan_info(scan_info); request_ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(request_ccb); break; @@ -2233,9 +2236,8 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb) "scsi_scan_bus: xpt_create_path failed with status %#x, bus scan halted\n", status); xpt_free_ccb(request_ccb); - xpt_free_ccb((union ccb *)scan_info->cpi); request_ccb = scan_info->request_ccb; - free(scan_info, M_CAMXPT); + free_scan_info(scan_info); request_ccb->ccb_h.status = status; xpt_done(request_ccb); break; @@ -2294,10 +2296,7 @@ scsi_scan_lun(struct cam_periph *periph, struct cam_path *path, CAM_DEBUG(path, CAM_DEBUG_TRACE, ("scsi_scan_lun\n")); - memset(&cpi, 0, sizeof(cpi)); - xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); + xpt_path_inq(&cpi, path); if (cpi.ccb_h.status != CAM_REQ_CMP) { if (request_ccb != NULL) { @@ -2421,10 +2420,7 @@ scsi_devise_transport(struct cam_path *path) struct scsi_inquiry_data *inq_buf; /* Get transport information from the SIM */ - memset(&cpi, 0, sizeof(cpi)); - xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); + xpt_path_inq(&cpi, path); inq_buf = NULL; if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) @@ -2732,10 +2728,7 @@ scsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_path *path inq_data = &device->inq_data; scsi = &cts->proto_specific.scsi; - memset(&cpi, 0, sizeof(cpi)); - xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); + xpt_path_inq(&cpi, path); /* SCSI specific sanity checking */ if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 @@ -3046,10 +3039,7 @@ _scsi_announce_periph(struct cam_periph *periph, u_int *speed, u_int *freq, stru return; /* Ask the SIM for its base transfer speed */ - memset(&cpi, 0, sizeof(cpi)); - xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); + xpt_path_inq(&cpi, path); /* Report connection speed */ *speed = cpi.base_transfer_speed; diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index 0ce38384abbf..83d964360343 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -2019,6 +2019,7 @@ typedef struct vdev { vdev_list_t v_children; /* children of this vdev */ const char *v_name; /* vdev name */ uint64_t v_guid; /* vdev guid */ + uint64_t v_txg; /* most recent transaction */ uint64_t v_id; /* index in parent */ uint64_t v_psize; /* physical device capacity */ int v_ashift; /* offset to block shift */ @@ -2048,7 +2049,6 @@ typedef struct spa { STAILQ_ENTRY(spa) spa_link; /* link in global pool list */ char *spa_name; /* pool name */ uint64_t spa_guid; /* pool guid */ - uint64_t spa_txg; /* most recent transaction */ struct uberblock *spa_uberblock; /* best uberblock so far */ vdev_t *spa_root_vdev; /* toplevel vdev container */ objset_phys_t *spa_mos; /* MOS for this pool */ diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 3718a1b0c8ee..ef0aff8bf852 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -659,7 +659,7 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */ { .sy_narg = AS(freebsd32_setcred_args), .sy_call = (sy_call_t *)freebsd32_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = freebsd32_setcred */ - { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ + { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */ }; diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h index f3a840d9bf4b..efa5c8cb67b3 100644 --- a/sys/compat/linuxkpi/common/include/linux/slab.h +++ b/sys/compat/linuxkpi/common/include/linux/slab.h @@ -45,7 +45,7 @@ MALLOC_DECLARE(M_KMALLOC); -#define kvzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO) +#define kvzalloc(size, flags) kvmalloc(size, (flags) | __GFP_ZERO) #define kvcalloc(n, size, flags) kvmalloc_array(n, size, (flags) | __GFP_ZERO) #define kzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO) #define kzalloc_node(size, flags, node) kmalloc_node(size, (flags) | __GFP_ZERO, node) diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c index ebb92eacbf9a..628af17df853 100644 --- a/sys/compat/linuxkpi/common/src/linux_page.c +++ b/sys/compat/linuxkpi/common/src/linux_page.c @@ -106,6 +106,7 @@ linux_alloc_pages(gfp_t flags, unsigned int order) if ((flags & M_ZERO) != 0) req |= VM_ALLOC_ZERO; + if (order == 0 && (flags & GFP_DMA32) == 0) { page = vm_page_alloc_noobj(req); if (page == NULL) @@ -113,6 +114,10 @@ linux_alloc_pages(gfp_t flags, unsigned int order) } else { vm_paddr_t pmax = (flags & GFP_DMA32) ? BUS_SPACE_MAXADDR_32BIT : BUS_SPACE_MAXADDR; + + if ((flags & __GFP_NORETRY) != 0) + req |= VM_ALLOC_NORECLAIM; + retry: page = vm_page_alloc_noobj_contig(req, npages, 0, pmax, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); diff --git a/sys/conf/files b/sys/conf/files index dd6f9a3021d4..dd0d390962f2 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -598,42 +598,24 @@ contrib/dev/acpica/components/utilities/utxface.c optional acpi contrib/dev/acpica/components/utilities/utxferror.c optional acpi contrib/dev/acpica/components/utilities/utxfinit.c optional acpi contrib/dev/acpica/os_specific/service_layers/osgendbg.c optional acpi acpi_debug -netpfil/ipfilter/netinet/fil.c optional ipfilter inet \ - compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_auth.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_fil_freebsd.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_frag.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_log.c optional ipfilter inet \ - compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_nat.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_proxy.c optional ipfilter inet \ - compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_state.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_lookup.c optional ipfilter inet \ - compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -Wno-error -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_pool.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_htable.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter ${NO_WTAUTOLOGICAL_POINTER_COMPARE}" -netpfil/ipfilter/netinet/ip_sync.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet \ - compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_nat6.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_rules.c optional ipfilter inet \ - compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_scan.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/ip_dstlist.c optional ipfilter inet \ - compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" -netpfil/ipfilter/netinet/radix_ipf.c optional ipfilter inet \ - compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" +netpfil/ipfilter/netinet/fil.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_auth.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_fil_freebsd.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_frag.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_log.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_nat.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_proxy.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_state.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_lookup.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_pool.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_htable.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_sync.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_nat6.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_rules.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_scan.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/ip_dstlist.c optional ipfilter inet compile-with "${IPFILTER_C}" +netpfil/ipfilter/netinet/radix_ipf.c optional ipfilter inet compile-with "${IPFILTER_C}" contrib/libfdt/fdt.c optional fdt contrib/libfdt/fdt_ro.c optional fdt contrib/libfdt/fdt_rw.c optional fdt @@ -3173,8 +3155,6 @@ dev/sound/midi/midi.c optional sound dev/sound/midi/mpu401.c optional sound dev/sound/midi/mpu_if.m optional sound dev/sound/midi/mpufoi_if.m optional sound -dev/sound/midi/sequencer.c optional sound -dev/sound/midi/synth_if.m optional sound dev/spibus/acpi_spibus.c optional acpi spibus dev/spibus/ofw_spibus.c optional fdt spibus dev/spibus/spibus.c optional spibus \ @@ -3247,6 +3227,19 @@ dev/uart/uart_if.m optional uart dev/uart/uart_subr.c optional uart dev/uart/uart_tty.c optional uart # +# Universal Flash Storage Host Controller Interface drivers +# +dev/ufshci/ufshci.c optional ufshci +dev/ufshci/ufshci_ctrlr.c optional ufshci +dev/ufshci/ufshci_ctrlr_cmd.c optional ufshci +dev/ufshci/ufshci_dev.c optional ufshci +dev/ufshci/ufshci_pci.c optional ufshci +dev/ufshci/ufshci_req_queue.c optional ufshci +dev/ufshci/ufshci_req_sdb.c optional ufshci +dev/ufshci/ufshci_sim.c optional ufshci +dev/ufshci/ufshci_sysctl.c optional ufshci +dev/ufshci/ufshci_uic_cmd.c optional ufshci +# # USB controller drivers # dev/usb/controller/musb_otg.c optional musb diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index e6e42b33a9b7..78178065e15b 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -290,6 +290,10 @@ BNXT_CFLAGS= -I$S/dev/bnxt/bnxt_en ${OFEDCFLAGS} BNXT_C_NOIMP= ${CC} -c -o ${.TARGET} ${BNXT_CFLAGS} ${WERROR} BNXT_C= ${BNXT_C_NOIMP} ${.IMPSRC} +# IP Filter +IPFILTER_CFLAGS= -I$S/netpfil/ipfilter +IPFILTER_C= ${NORMAL_C} ${IPFILTER_CFLAGS} + GEN_CFILES= $S/$M/$M/genassym.c ${MFILES:T:S/.m$/.c/} SYSTEM_CFILES= config.c env.c hints.c vnode_if.c SYSTEM_DEP= Makefile ${SYSTEM_OBJS} diff --git a/sys/dev/gpio/acpi_gpiobus.c b/sys/dev/gpio/acpi_gpiobus.c index f9468e0deda0..94f4e5771266 100644 --- a/sys/dev/gpio/acpi_gpiobus.c +++ b/sys/dev/gpio/acpi_gpiobus.c @@ -357,7 +357,7 @@ acpi_gpiobus_attach(device_t dev) status = AcpiWalkResources(handle, "_AEI", acpi_gpiobus_enumerate_aei, &ctx); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) device_printf(dev, "Failed to enumerate AEI resources\n"); return (0); diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index ab7f13177969..764bcb7e6ee8 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -110,10 +110,9 @@ gpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags, res = bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid, irq, irq, 1, alloc_flags); if (res == NULL) { - intr_free_intr_map_data((struct intr_map_data *)gpio_data); + intr_unmap_irq(irq); return (NULL); } - rman_set_virtual(res, gpio_data); return (res); } #else @@ -866,6 +865,25 @@ gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, end, count, flags)); } +static int +gpiobus_release_resource(device_t dev, device_t child, struct resource *r) +{ + int err; +#ifdef INTRNG + u_int irq; + + irq = rman_get_start(r); + MPASS(irq == rman_get_end(r)); +#endif + err = bus_generic_rman_release_resource(dev, child, r); + if (err != 0) + return (err); +#ifdef INTRNG + intr_unmap_irq(irq); +#endif + return (0); +} + static struct resource_list * gpiobus_get_resource_list(device_t bus __unused, device_t child) { @@ -1060,7 +1078,7 @@ static device_method_t gpiobus_methods[] = { DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_alloc_resource, gpiobus_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_rman_release_resource), + DEVMETHOD(bus_release_resource, gpiobus_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_rman_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_rman_deactivate_resource), DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list), diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c index 189a3e66a039..7ea60a499c72 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chan.c +++ b/sys/dev/hyperv/vmbus/vmbus_chan.c @@ -1555,7 +1555,7 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags, continue; flags = atomic_swap_long(&event_flags[f], 0); - chid_base = f << VMBUS_EVTFLAG_SHIFT; + chid_base = f * VMBUS_EVTFLAG_LEN; while ((chid_ofs = ffsl(flags)) != 0) { struct vmbus_channel *chan; @@ -1599,7 +1599,7 @@ vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu) eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE; if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) { vmbus_event_flags_proc(sc, sc->vmbus_rx_evtflags, - VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT); + VMBUS_CHAN_MAX_COMPAT / VMBUS_EVTFLAG_LEN); } } @@ -1903,7 +1903,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc, * Setup event flag. */ chan->ch_evtflag = - &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT]; + &sc->vmbus_tx_evtflags[chan->ch_id / VMBUS_EVTFLAG_LEN]; chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK); /* diff --git a/sys/dev/hyperv/vmbus/vmbus_reg.h b/sys/dev/hyperv/vmbus/vmbus_reg.h index 4aa729475b5d..76cdca0ebeb2 100644 --- a/sys/dev/hyperv/vmbus/vmbus_reg.h +++ b/sys/dev/hyperv/vmbus/vmbus_reg.h @@ -60,16 +60,10 @@ CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE); * Hyper-V SynIC event flags */ -#ifdef __LP64__ -#define VMBUS_EVTFLAGS_MAX 32 -#define VMBUS_EVTFLAG_SHIFT 6 -#else -#define VMBUS_EVTFLAGS_MAX 64 -#define VMBUS_EVTFLAG_SHIFT 5 -#endif -#define VMBUS_EVTFLAG_LEN (1 << VMBUS_EVTFLAG_SHIFT) +#define VMBUS_EVTFLAG_LEN (sizeof(u_long) * 8) #define VMBUS_EVTFLAG_MASK (VMBUS_EVTFLAG_LEN - 1) #define VMBUS_EVTFLAGS_SIZE 256 +#define VMBUS_EVTFLAGS_MAX (VMBUS_EVTFLAGS_SIZE / sizeof(u_long)) struct vmbus_evtflags { u_long evt_flags[VMBUS_EVTFLAGS_MAX]; diff --git a/sys/dev/ichiic/ig4_pci.c b/sys/dev/ichiic/ig4_pci.c index 0195466150eb..3a49e220e335 100644 --- a/sys/dev/ichiic/ig4_pci.c +++ b/sys/dev/ichiic/ig4_pci.c @@ -186,6 +186,12 @@ static int ig4iic_pci_detach(device_t dev); #define PCI_CHIP_METEORLAKE_M_I2C_3 0x7e518086 #define PCI_CHIP_METEORLAKE_M_I2C_4 0x7e7a8086 #define PCI_CHIP_METEORLAKE_M_I2C_5 0x7e7b8086 +#define PCI_CHIP_ARROWLAKE_U_I2C_0 0x77788086 +#define PCI_CHIP_ARROWLAKE_U_I2C_1 0x77798086 +#define PCI_CHIP_ARROWLAKE_U_I2C_2 0x777a8086 +#define PCI_CHIP_ARROWLAKE_U_I2C_3 0x777b8086 +#define PCI_CHIP_ARROWLAKE_U_I2C_4 0x77508086 +#define PCI_CHIP_ARROWLAKE_U_I2C_5 0x77518086 struct ig4iic_pci_device { uint32_t devid; @@ -316,6 +322,12 @@ static struct ig4iic_pci_device ig4iic_pci_devices[] = { { PCI_CHIP_METEORLAKE_M_I2C_3, "Intel Meteor Lake-M I2C Controller-3", IG4_TIGERLAKE}, { PCI_CHIP_METEORLAKE_M_I2C_4, "Intel Meteor Lake-M I2C Controller-4", IG4_TIGERLAKE}, { PCI_CHIP_METEORLAKE_M_I2C_5, "Intel Meteor Lake-M I2C Controller-5", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_0, "Intel Arrow Lake-H/U I2C Controller-0", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_1, "Intel Arrow Lake-H/U I2C Controller-1", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_2, "Intel Arrow Lake-H/U I2C Controller-2", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_3, "Intel Arrow Lake-H/U I2C Controller-3", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_4, "Intel Arrow Lake-H/U I2C Controller-4", IG4_TIGERLAKE}, + { PCI_CHIP_ARROWLAKE_U_I2C_5, "Intel Arrow Lake-H/U I2C Controller-5", IG4_TIGERLAKE}, }; static int diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index 741a7c013f7d..29dc0c880e3a 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -11,9 +11,9 @@ */ /*- - * The following functions are based on the vn(4) driver: mdstart_swap(), - * mdstart_vnode(), mdcreate_swap(), mdcreate_vnode() and mddestroy(), - * and as such under the following copyright: + * The following functions are based on the historical vn(4) driver: + * mdstart_swap(), mdstart_vnode(), mdcreate_swap(), mdcreate_vnode() + * and mddestroy(), and as such under the following copyright: * * Copyright (c) 1988 University of Utah. * Copyright (c) 1990, 1993 diff --git a/sys/dev/mgb/if_mgb.c b/sys/dev/mgb/if_mgb.c index 1240d0f84415..409f34167df0 100644 --- a/sys/dev/mgb/if_mgb.c +++ b/sys/dev/mgb/if_mgb.c @@ -1435,7 +1435,7 @@ mgb_hw_teardown(struct mgb_softc *sc) /* Stop MAC */ CSR_CLEAR_REG(sc, MGB_MAC_RX, MGB_MAC_ENBL); - CSR_WRITE_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL); + CSR_CLEAR_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL); if ((err = mgb_wait_for_bits(sc, MGB_MAC_RX, MGB_MAC_DSBL, 0))) return (err); if ((err = mgb_wait_for_bits(sc, MGB_MAC_TX, MGB_MAC_DSBL, 0))) diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c index 8b8f2e570245..89d2010656c5 100644 --- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c @@ -42,13 +42,30 @@ static if_snd_tag_free_t mlx5e_tls_rx_snd_tag_free; static if_snd_tag_modify_t mlx5e_tls_rx_snd_tag_modify; +static if_snd_tag_status_str_t mlx5e_tls_rx_snd_tag_status_str; static const struct if_snd_tag_sw mlx5e_tls_rx_snd_tag_sw = { .snd_tag_modify = mlx5e_tls_rx_snd_tag_modify, .snd_tag_free = mlx5e_tls_rx_snd_tag_free, + .snd_tag_status_str = mlx5e_tls_rx_snd_tag_status_str, .type = IF_SND_TAG_TYPE_TLS_RX }; +static const char *mlx5e_tls_rx_progress_params_auth_state_str[] = { + [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_NO_OFFLOAD] = "no_offload", + [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_OFFLOAD] = "offload", + [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION] = + "authentication", +}; + +static const char *mlx5e_tls_rx_progress_params_record_tracker_state_str[] = { + [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START] = "start", + [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING] = + "tracking", + [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING] = + "searching", +}; + MALLOC_DEFINE(M_MLX5E_TLS_RX, "MLX5E_TLS_RX", "MLX5 ethernet HW TLS RX"); /* software TLS RX context */ @@ -250,7 +267,8 @@ mlx5e_tls_rx_send_progress_parameters_sync(struct mlx5e_iq *iq, mtx_unlock(&iq->lock); while (1) { - if (wait_for_completion_timeout(&ptag->progress_complete, hz) != 0) + if (wait_for_completion_timeout(&ptag->progress_complete, + msecs_to_jiffies(1000)) != 0) break; priv = container_of(iq, struct mlx5e_channel, iq)->priv; if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR || @@ -331,7 +349,8 @@ done: * Zero is returned upon success, else some error happened. */ static int -mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_rx_tag *ptag) +mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, + struct mlx5e_tls_rx_tag *ptag, mlx5e_iq_callback_t *cb) { struct mlx5e_get_tls_progress_params_wqe *wqe; const u32 ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS); @@ -367,7 +386,7 @@ mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_r memcpy(iq->doorbell.d32, &wqe->ctrl, sizeof(iq->doorbell.d32)); iq->data[pi].num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS); - iq->data[pi].callback = &mlx5e_tls_rx_receive_progress_parameters_cb; + iq->data[pi].callback = cb; iq->data[pi].arg = ptag; m_snd_tag_ref(&ptag->tag); @@ -640,7 +659,8 @@ mlx5e_tls_rx_set_params(void *ctx, struct inpcb *inp, const struct tls_session_p return (EINVAL); MLX5_SET64(sw_tls_rx_cntx, ctx, param.initial_record_number, tls_sn_he); - MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, tcp_sn_he); + MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, 0); + MLX5_SET(sw_tls_rx_cntx, ctx, progress.next_record_tcp_sn, tcp_sn_he); return (0); } @@ -819,6 +839,7 @@ mlx5e_tls_rx_snd_tag_alloc(if_t ifp, } ptag->flow_rule = flow_rule; + init_completion(&ptag->progress_complete); return (0); @@ -968,7 +989,8 @@ mlx5e_tls_rx_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_param params->tls_rx.tls_rec_length, params->tls_rx.tls_seq_number) && ptag->tcp_resync_pending == 0) { - err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag); + err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag, + &mlx5e_tls_rx_receive_progress_parameters_cb); if (err != 0) { MLX5E_TLS_RX_STAT_INC(ptag, rx_resync_err, 1); } else { @@ -1001,6 +1023,74 @@ mlx5e_tls_rx_snd_tag_free(struct m_snd_tag *pmt) queue_work(priv->tls_rx.wq, &ptag->work); } +static void +mlx5e_tls_rx_str_status_cb(void *arg) +{ + struct mlx5e_tls_rx_tag *ptag; + + ptag = (struct mlx5e_tls_rx_tag *)arg; + complete_all(&ptag->progress_complete); + m_snd_tag_rele(&ptag->tag); +} + +static int +mlx5e_tls_rx_snd_tag_status_str(struct m_snd_tag *pmt, char *buf, size_t *sz) +{ + int err, out_size; + struct mlx5e_iq *iq; + void *buffer; + uint32_t tracker_state_val; + uint32_t auth_state_val; + struct mlx5e_priv *priv; + struct mlx5e_tls_rx_tag *ptag = + container_of(pmt, struct mlx5e_tls_rx_tag, tag); + + if (buf == NULL) + return (0); + + MLX5E_TLS_RX_TAG_LOCK(ptag); + priv = container_of(ptag->tls_rx, struct mlx5e_priv, tls_rx); + iq = mlx5e_tls_rx_get_iq(priv, ptag->flowid, ptag->flowtype); + reinit_completion(&ptag->progress_complete); + err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag, + &mlx5e_tls_rx_str_status_cb); + MLX5E_TLS_RX_TAG_UNLOCK(ptag); + if (err != 0) + return (err); + + for (;;) { + if (wait_for_completion_timeout(&ptag->progress_complete, + msecs_to_jiffies(1000)) != 0) + break; + if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR || + pci_channel_offline(priv->mdev->pdev) != 0) + return (ENXIO); + } + buffer = mlx5e_tls_rx_get_progress_buffer(ptag); + tracker_state_val = MLX5_GET(tls_progress_params, buffer, + record_tracker_state); + auth_state_val = MLX5_GET(tls_progress_params, buffer, auth_state); + + /* Validate tracker state value is in range */ + if (tracker_state_val > + MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING) + return (EINVAL); + + /* Validate auth state value is in range */ + if (auth_state_val > + MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION) + return (EINVAL); + + out_size = snprintf(buf, *sz, "tracker_state: %s, auth_state: %s", + mlx5e_tls_rx_progress_params_record_tracker_state_str[ + tracker_state_val], + mlx5e_tls_rx_progress_params_auth_state_str[auth_state_val]); + + if (out_size <= *sz) + *sz = out_size; + return (0); +} + #else int diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c index dbdd4568bdf1..1ac0d142443b 100644 --- a/sys/dev/nvmf/host/nvmf.c +++ b/sys/dev/nvmf/host/nvmf.c @@ -27,6 +27,7 @@ #include <dev/nvmf/host/nvmf_var.h> static struct cdevsw nvmf_cdevsw; +static struct taskqueue *nvmf_tq; bool nvmf_fail_disconnect = false; SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN, @@ -34,7 +35,10 @@ SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN, MALLOC_DEFINE(M_NVMF, "nvmf", "NVMe over Fabrics host"); +static void nvmf_controller_loss_task(void *arg, int pending); static void nvmf_disconnect_task(void *arg, int pending); +static void nvmf_request_reconnect(struct nvmf_softc *sc); +static void nvmf_request_reconnect_task(void *arg, int pending); static void nvmf_shutdown_pre_sync(void *arg, int howto); static void nvmf_shutdown_post_sync(void *arg, int howto); @@ -294,6 +298,9 @@ nvmf_establish_connection(struct nvmf_softc *sc, nvlist_t *nvl) admin = nvlist_get_nvlist(nvl, "admin"); io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues); kato = dnvlist_get_number(nvl, "kato", 0); + sc->reconnect_delay = dnvlist_get_number(nvl, "reconnect_delay", 0); + sc->controller_loss_timeout = dnvlist_get_number(nvl, + "controller_loss_timeout", 0); /* Setup the admin queue. */ sc->admin = nvmf_init_qp(sc, trtype, admin, "admin queue", 0); @@ -504,6 +511,10 @@ nvmf_attach(device_t dev) callout_init(&sc->ka_tx_timer, 1); sx_init(&sc->connection_lock, "nvmf connection"); TASK_INIT(&sc->disconnect_task, 0, nvmf_disconnect_task, sc); + TIMEOUT_TASK_INIT(nvmf_tq, &sc->controller_loss_task, 0, + nvmf_controller_loss_task, sc); + TIMEOUT_TASK_INIT(nvmf_tq, &sc->request_reconnect_task, 0, + nvmf_request_reconnect_task, sc); oid = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ioq", @@ -603,7 +614,9 @@ out: nvmf_destroy_aer(sc); - taskqueue_drain(taskqueue_thread, &sc->disconnect_task); + taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task); + taskqueue_drain_timeout(nvmf_tq, &sc->controller_loss_task); + taskqueue_drain(nvmf_tq, &sc->disconnect_task); sx_destroy(&sc->connection_lock); nvlist_destroy(sc->rparams); free(sc->cdata, M_NVMF); @@ -613,7 +626,7 @@ out: void nvmf_disconnect(struct nvmf_softc *sc) { - taskqueue_enqueue(taskqueue_thread, &sc->disconnect_task); + taskqueue_enqueue(nvmf_tq, &sc->disconnect_task); } static void @@ -676,6 +689,74 @@ nvmf_disconnect_task(void *arg, int pending __unused) nvmf_destroy_qp(sc->admin); sc->admin = NULL; + if (sc->reconnect_delay != 0) + nvmf_request_reconnect(sc); + if (sc->controller_loss_timeout != 0) + taskqueue_enqueue_timeout(nvmf_tq, + &sc->controller_loss_task, sc->controller_loss_timeout * + hz); + + sx_xunlock(&sc->connection_lock); +} + +static void +nvmf_controller_loss_task(void *arg, int pending) +{ + struct nvmf_softc *sc = arg; + device_t dev; + int error; + + bus_topo_lock(); + sx_xlock(&sc->connection_lock); + if (sc->admin != NULL || sc->detaching) { + /* Reconnected or already detaching. */ + sx_xunlock(&sc->connection_lock); + bus_topo_unlock(); + return; + } + + sc->controller_timedout = true; + sx_xunlock(&sc->connection_lock); + + /* + * XXX: Doing this from here is a bit ugly. We don't have an + * extra reference on `dev` but bus_topo_lock should block any + * concurrent device_delete_child invocations. + */ + dev = sc->dev; + error = device_delete_child(root_bus, dev); + if (error != 0) + device_printf(dev, + "failed to detach after controller loss: %d\n", error); + bus_topo_unlock(); +} + +static void +nvmf_request_reconnect(struct nvmf_softc *sc) +{ + char buf[64]; + + sx_assert(&sc->connection_lock, SX_LOCKED); + + snprintf(buf, sizeof(buf), "name=\"%s\"", device_get_nameunit(sc->dev)); + devctl_notify("nvme", "controller", "RECONNECT", buf); + taskqueue_enqueue_timeout(nvmf_tq, &sc->request_reconnect_task, + sc->reconnect_delay * hz); +} + +static void +nvmf_request_reconnect_task(void *arg, int pending) +{ + struct nvmf_softc *sc = arg; + + sx_xlock(&sc->connection_lock); + if (sc->admin != NULL || sc->detaching || sc->controller_timedout) { + /* Reconnected or already detaching. */ + sx_xunlock(&sc->connection_lock); + return; + } + + nvmf_request_reconnect(sc); sx_xunlock(&sc->connection_lock); } @@ -699,7 +780,7 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv) } sx_xlock(&sc->connection_lock); - if (sc->admin != NULL || sc->detaching) { + if (sc->admin != NULL || sc->detaching || sc->controller_timedout) { error = EBUSY; goto out; } @@ -745,6 +826,9 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv) nvmf_reconnect_sim(sc); nvmf_rescan_all_ns(sc); + + taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task, NULL); + taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task, NULL); out: sx_xunlock(&sc->connection_lock); nvlist_destroy(nvl); @@ -852,7 +936,21 @@ nvmf_detach(device_t dev) } free(sc->io, M_NVMF); - taskqueue_drain(taskqueue_thread, &sc->disconnect_task); + taskqueue_drain(nvmf_tq, &sc->disconnect_task); + if (taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task, + NULL) != 0) + taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task); + + /* + * Don't cancel/drain the controller loss task if that task + * has fired and is triggering the detach. + */ + if (!sc->controller_timedout) { + if (taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task, + NULL) != 0) + taskqueue_drain_timeout(nvmf_tq, + &sc->controller_loss_task); + } if (sc->admin != NULL) nvmf_destroy_qp(sc->admin); @@ -1154,14 +1252,25 @@ static struct cdevsw nvmf_cdevsw = { static int nvmf_modevent(module_t mod, int what, void *arg) { + int error; + switch (what) { case MOD_LOAD: - return (nvmf_ctl_load()); + error = nvmf_ctl_load(); + if (error != 0) + return (error); + + nvmf_tq = taskqueue_create("nvmf", M_WAITOK | M_ZERO, + taskqueue_thread_enqueue, &nvmf_tq); + taskqueue_start_threads(&nvmf_tq, 1, PWAIT, "nvmf taskq"); + return (0); case MOD_QUIESCE: return (0); case MOD_UNLOAD: nvmf_ctl_unload(); destroy_dev_drain(&nvmf_cdevsw); + if (nvmf_tq != NULL) + taskqueue_free(nvmf_tq); return (0); default: return (EOPNOTSUPP); diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h index e45a31f413a4..606245b3969c 100644 --- a/sys/dev/nvmf/host/nvmf_var.h +++ b/sys/dev/nvmf/host/nvmf_var.h @@ -75,9 +75,15 @@ struct nvmf_softc { struct callout ka_rx_timer; sbintime_t ka_rx_sbt; + struct timeout_task request_reconnect_task; + struct timeout_task controller_loss_task; + uint32_t reconnect_delay; + uint32_t controller_loss_timeout; + struct sx connection_lock; struct task disconnect_task; bool detaching; + bool controller_timedout; u_int num_aer; struct nvmf_aer *aer; diff --git a/sys/dev/nvmf/nvmf.h b/sys/dev/nvmf/nvmf.h index d4e7b1511e9d..9b2b4c1dea40 100644 --- a/sys/dev/nvmf/nvmf.h +++ b/sys/dev/nvmf/nvmf.h @@ -27,6 +27,13 @@ #define NVMF_NN (1024) /* + * Default timeouts for Fabrics hosts. These match values used by + * Linux. + */ +#define NVMF_DEFAULT_RECONNECT_DELAY 10 +#define NVMF_DEFAULT_CONTROLLER_LOSS 600 + +/* * (data, size) is the userspace buffer for a packed nvlist. * * For requests that copyout an nvlist, len is the amount of data @@ -68,6 +75,8 @@ struct nvmf_ioc_nv { * * number trtype * number kato (optional) + * number reconnect_delay (optional) + * number controller_loss_timeout (optional) * qpair handoff nvlist admin * qpair handoff nvlist array io * binary cdata struct nvme_controller_data @@ -81,6 +90,8 @@ struct nvmf_ioc_nv { * string hostnqn * number num_io_queues * number kato (optional) + * number reconnect_delay (optional) + * number controller_loss_timeout (optional) * number io_qsize * bool sq_flow_control * diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c index 05ec69a70dfe..9d23d5df1d2b 100644 --- a/sys/dev/qlnx/qlnxe/qlnx_os.c +++ b/sys/dev/qlnx/qlnxe/qlnx_os.c @@ -30,6 +30,8 @@ * Author : David C Somayajulu, Cavium, Inc., San Jose, CA 95131. */ +#include "opt_inet.h" + #include <sys/cdefs.h> #include "qlnx_os.h" #include "bcm_osal.h" @@ -2778,7 +2780,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data) if (!p_ptt) { QL_DPRINT1(ha, "ecore_ptt_acquire failed\n"); - ret = -1; + ret = ERESTART; break; } @@ -2789,7 +2791,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data) ecore_ptt_release(p_hwfn, p_ptt); if (ret) { - ret = -1; + ret = ENODEV; break; } diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index ee37bda36496..395310b115fb 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -131,30 +131,14 @@ static struct harvest_context { /* The context of the kernel thread processing harvested entropy */ struct proc *hc_kthread_proc; /* - * Lockless ring buffer holding entropy events - * If ring.in == ring.out, - * the buffer is empty. - * If ring.in != ring.out, - * the buffer contains harvested entropy. - * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX), - * the buffer is full. - * - * NOTE: ring.in points to the last added element, - * and ring.out points to the last consumed element. - * - * The ring.in variable needs locking as there are multiple - * sources to the ring. Only the sources may change ring.in, - * but the consumer may examine it. - * - * The ring.out variable does not need locking as there is - * only one consumer. Only the consumer may change ring.out, - * but the sources may examine it. + * A pair of buffers for queued events. New events are added to the + * active queue while the kthread processes the other one in parallel. */ - struct entropy_ring { + struct entropy_buffer { struct harvest_event ring[RANDOM_RING_MAX]; - volatile u_int in; - volatile u_int out; - } hc_entropy_ring; + u_int pos; + } hc_entropy_buf[2]; + u_int hc_active_buf; struct fast_entropy_accumulator { volatile u_int pos; uint32_t buf[RANDOM_ACCUM_MAX]; @@ -183,37 +167,41 @@ random_harvestq_fast_process_event(struct harvest_event *event) static void random_kthread(void) { - u_int maxloop, ring_out, i; + struct harvest_context *hc; - /* - * Locking is not needed as this is the only place we modify ring.out, and - * we only examine ring.in without changing it. Both of these are volatile, - * and this is a unique thread. - */ + hc = &harvest_context; for (random_kthread_control = 1; random_kthread_control;) { - /* Deal with events, if any. Restrict the number we do in one go. */ - maxloop = RANDOM_RING_MAX; - while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) { - ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX; - random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out); - harvest_context.hc_entropy_ring.out = ring_out; - if (!--maxloop) - break; - } + struct entropy_buffer *buf; + u_int entries; + + /* Deal with queued events. */ + RANDOM_HARVEST_LOCK(); + buf = &hc->hc_entropy_buf[hc->hc_active_buf]; + entries = buf->pos; + buf->pos = 0; + hc->hc_active_buf = (hc->hc_active_buf + 1) % + nitems(hc->hc_entropy_buf); + RANDOM_HARVEST_UNLOCK(); + for (u_int i = 0; i < entries; i++) + random_harvestq_fast_process_event(&buf->ring[i]); + + /* Poll sources of noise. */ random_sources_feed(); + /* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ - for (i = 0; i < RANDOM_ACCUM_MAX; i++) { - if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { - random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA); - harvest_context.hc_entropy_fast_accumulator.buf[i] = 0; + for (u_int i = 0; i < RANDOM_ACCUM_MAX; i++) { + if (hc->hc_entropy_fast_accumulator.buf[i]) { + random_harvest_direct(&hc->hc_entropy_fast_accumulator.buf[i], + sizeof(hc->hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA); + hc->hc_entropy_fast_accumulator.buf[i] = 0; } } /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ - tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", + tsleep_sbt(&hc->hc_kthread_proc, 0, "-", SBT_1S/RANDOM_KTHREAD_HZ, 0, C_PREL(1)); } random_kthread_control = -1; - wakeup(&harvest_context.hc_kthread_proc); + wakeup(&hc->hc_kthread_proc); kproc_exit(0); /* NOTREACHED */ } @@ -435,7 +423,7 @@ random_harvestq_init(void *unused __unused) hc_source_mask = almost_everything_mask; RANDOM_HARVEST_INIT_LOCK(); - harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; + harvest_context.hc_active_buf = 0; } SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_init, NULL); @@ -540,9 +528,9 @@ SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_d * This is supposed to be fast; do not do anything slow in here! * It is also illegal (and morally reprehensible) to insert any * high-rate data here. "High-rate" is defined as a data source - * that will usually cause lots of failures of the "Lockless read" - * check a few lines below. This includes the "always-on" sources - * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. + * that is likely to fill up the buffer in much less than 100ms. + * This includes the "always-on" sources like the Intel "rdrand" + * or the VIA Nehamiah "xstore" sources. */ /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle * counters are built in, but on older hardware it will do a real time clock @@ -551,28 +539,29 @@ SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_d void random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin) { + struct harvest_context *hc; + struct entropy_buffer *buf; struct harvest_event *event; - u_int ring_in; - KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); + KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, + ("%s: origin %d invalid", __func__, origin)); + + hc = &harvest_context; RANDOM_HARVEST_LOCK(); - ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX; - if (ring_in != harvest_context.hc_entropy_ring.out) { - /* The ring is not full */ - event = harvest_context.hc_entropy_ring.ring + ring_in; + buf = &hc->hc_entropy_buf[hc->hc_active_buf]; + if (buf->pos < RANDOM_RING_MAX) { + event = &buf->ring[buf->pos++]; event->he_somecounter = random_get_cyclecount(); event->he_source = origin; - event->he_destination = harvest_context.hc_destination[origin]++; + event->he_destination = hc->hc_destination[origin]++; if (size <= sizeof(event->he_entropy)) { event->he_size = size; memcpy(event->he_entropy, entropy, size); - } - else { + } else { /* Big event, so squash it */ event->he_size = sizeof(event->he_entropy[0]); event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); } - harvest_context.hc_entropy_ring.in = ring_in; } RANDOM_HARVEST_UNLOCK(); } diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c index fbfb69de2913..6753f864ba9c 100644 --- a/sys/dev/sound/midi/midi.c +++ b/sys/dev/sound/midi/midi.c @@ -30,12 +30,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - /* - * Parts of this file started out as NetBSD: midi.c 1.31 - * They are mostly gone. Still the most obvious will be the state - * machine midi_in - */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/queue.h> @@ -66,7 +60,6 @@ #include "mpu_if.h" #include <dev/sound/midi/midiq.h> -#include "synth_if.h" MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area"); #ifndef KOBJMETHOD_END @@ -79,17 +72,6 @@ enum midi_states { MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA }; -/* - * The MPU interface current has init() uninit() inqsize() outqsize() - * callback() : fiddle with the tx|rx status. - */ - -#include "mpu_if.h" - -/* - * /dev/rmidi Structure definitions - */ - #define MIDI_NAMELEN 16 struct snd_midi { KOBJ_FIELDS; @@ -115,95 +97,13 @@ struct snd_midi { * complete command packets. */ struct proc *async; struct cdev *dev; - struct synth_midi *synth; - int synth_flags; TAILQ_ENTRY(snd_midi) link; }; -struct synth_midi { - KOBJ_FIELDS; - struct snd_midi *m; -}; - -static synth_open_t midisynth_open; -static synth_close_t midisynth_close; -static synth_writeraw_t midisynth_writeraw; -static synth_killnote_t midisynth_killnote; -static synth_startnote_t midisynth_startnote; -static synth_setinstr_t midisynth_setinstr; -static synth_alloc_t midisynth_alloc; -static synth_controller_t midisynth_controller; -static synth_bender_t midisynth_bender; - -static kobj_method_t midisynth_methods[] = { - KOBJMETHOD(synth_open, midisynth_open), - KOBJMETHOD(synth_close, midisynth_close), - KOBJMETHOD(synth_writeraw, midisynth_writeraw), - KOBJMETHOD(synth_setinstr, midisynth_setinstr), - KOBJMETHOD(synth_startnote, midisynth_startnote), - KOBJMETHOD(synth_killnote, midisynth_killnote), - KOBJMETHOD(synth_alloc, midisynth_alloc), - KOBJMETHOD(synth_controller, midisynth_controller), - KOBJMETHOD(synth_bender, midisynth_bender), - KOBJMETHOD_END -}; - -DEFINE_CLASS(midisynth, midisynth_methods, 0); - -/* - * Module Exports & Interface - * - * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan, - * void *cookie) - * int midi_uninit(struct snd_midi *) - * - * 0 == no error - * EBUSY or other error - * - * int midi_in(struct snd_midi *, char *buf, int count) - * int midi_out(struct snd_midi *, char *buf, int count) - * - * midi_{in,out} return actual size transfered - * - */ - -/* - * midi_devs tailq, holder of all rmidi instances protected by midistat_lock - */ - TAILQ_HEAD(, snd_midi) midi_devs; -/* - * /dev/midistat variables and declarations, protected by midistat_lock - */ - struct sx mstat_lock; -static int midistat_isopen = 0; -static struct sbuf midistat_sbuf; -static struct cdev *midistat_dev; - -/* - * /dev/midistat dev_t declarations - */ - -static d_open_t midistat_open; -static d_close_t midistat_close; -static d_read_t midistat_read; - -static struct cdevsw midistat_cdevsw = { - .d_version = D_VERSION, - .d_open = midistat_open, - .d_close = midistat_close, - .d_read = midistat_read, - .d_name = "midistat", -}; - -/* - * /dev/rmidi dev_t declarations, struct variable access is protected by - * locks contained within the structure. - */ - static d_open_t midi_open; static d_close_t midi_close; static d_ioctl_t midi_ioctl; @@ -222,41 +122,18 @@ static struct cdevsw midi_cdevsw = { .d_name = "rmidi", }; -/* - * Prototypes of library functions - */ - static int midi_destroy(struct snd_midi *, int); -static int midistat_prepare(struct sbuf * s); static int midi_load(void); static int midi_unload(void); -/* - * Misc declr. - */ SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Midi driver"); -static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, - "Status device"); int midi_debug; /* XXX: should this be moved into debug.midi? */ SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); -int midi_dumpraw; -SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, ""); - -int midi_instroff; -SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, ""); - -int midistat_verbose; -SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW, - &midistat_verbose, 0, ""); - #define MIDI_DEBUG(l,a) if(midi_debug>=l) a -/* - * CODE START - */ void midistat_lock(void) @@ -285,9 +162,6 @@ midistat_lockassert(void) * what unit number is used. * * It is an error to call midi_init with an already used unit/channel combo. - * - * Returns NULL on error - * */ struct snd_midi * midi_init(kobj_class_t cls, int unit, int channel, void *cookie) @@ -326,9 +200,6 @@ midi_init(kobj_class_t cls, int unit, int channel, void *cookie) MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel)); m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO); - m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO); - kobj_init((kobj_t)m->synth, &midisynth_class); - m->synth->m = m; kobj_init((kobj_t)m, cls); inqsize = MPU_INQSIZE(m, cookie); outqsize = MPU_OUTQSIZE(m, cookie); @@ -393,7 +264,6 @@ err2: if (MIDIQ_BUF(m->outq)) free(MIDIQ_BUF(m->outq), M_MIDI); err1: - free(m->synth, M_MIDI); free(m, M_MIDI); err0: midistat_unlock(); @@ -405,9 +275,7 @@ err0: * midi_uninit does not call MIDI_UNINIT, as since this is the implementors * entry point. midi_uninit if fact, does not send any methods. A call to * midi_uninit is a defacto promise that you won't manipulate ch anymore - * */ - int midi_uninit(struct snd_midi *m) { @@ -440,13 +308,6 @@ exit: return err; } -/* - * midi_in: process all data until the queue is full, then discards the rest. - * Since midi_in is a state machine, data discards can cause it to get out of - * whack. Process as much as possible. It calls, wakeup, selnotify and - * psignal at most once. - */ - #ifdef notdef static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0}; @@ -460,6 +321,12 @@ static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0}; #define MIDI_SYSEX_START 0xF0 #define MIDI_SYSEX_END 0xF7 +/* + * midi_in: process all data until the queue is full, then discards the rest. + * Since midi_in is a state machine, data discards can cause it to get out of + * whack. Process as much as possible. It calls, wakeup, selnotify and + * psignal at most once. + */ int midi_in(struct snd_midi *m, uint8_t *buf, int size) { @@ -627,9 +494,6 @@ midi_out(struct snd_midi *m, uint8_t *buf, int size) return used; } -/* - * /dev/rmidi#.# device access functions - */ int midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td) { @@ -934,434 +798,6 @@ midi_poll(struct cdev *i_dev, int events, struct thread *td) } /* - * /dev/midistat device functions - * - */ -static int -midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td) -{ - int error; - - MIDI_DEBUG(1, printf("midistat_open\n")); - - midistat_lock(); - if (midistat_isopen) { - midistat_unlock(); - return EBUSY; - } - midistat_isopen = 1; - sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND); - error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM; - if (error) - midistat_isopen = 0; - midistat_unlock(); - return error; -} - -static int -midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td) -{ - MIDI_DEBUG(1, printf("midistat_close\n")); - midistat_lock(); - if (!midistat_isopen) { - midistat_unlock(); - return EBADF; - } - sbuf_delete(&midistat_sbuf); - midistat_isopen = 0; - midistat_unlock(); - return 0; -} - -static int -midistat_read(struct cdev *i_dev, struct uio *uio, int flag) -{ - long l; - int err; - - MIDI_DEBUG(4, printf("midistat_read\n")); - midistat_lock(); - if (!midistat_isopen) { - midistat_unlock(); - return EBADF; - } - if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) { - midistat_unlock(); - return EINVAL; - } - err = 0; - l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset); - if (l > 0) { - err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l, - uio); - } - midistat_unlock(); - return err; -} - -/* - * Module library functions - */ - -static int -midistat_prepare(struct sbuf *s) -{ - struct snd_midi *m; - - midistat_lockassert(); - - sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n"); - if (TAILQ_EMPTY(&midi_devs)) { - sbuf_printf(s, "No devices installed.\n"); - sbuf_finish(s); - return sbuf_len(s); - } - sbuf_printf(s, "Installed devices:\n"); - - TAILQ_FOREACH(m, &midi_devs, link) { - mtx_lock(&m->lock); - sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel, - MPU_PROVIDER(m, m->cookie)); - sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose)); - sbuf_printf(s, "\n"); - mtx_unlock(&m->lock); - } - - sbuf_finish(s); - return sbuf_len(s); -} - -#ifdef notdef -/* - * Convert IOCTL command to string for debugging - */ - -static char * -midi_cmdname(int cmd) -{ - static struct { - int cmd; - char *name; - } *tab, cmdtab_midiioctl[] = { -#define A(x) {x, ## x} - /* - * Once we have some real IOCTLs define, the following will - * be relavant. - * - * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE), - * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO), - * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL), - * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE), - * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE), - * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT), - * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC), - * A(AIOGCAP), - */ -#undef A - { - -1, "unknown" - }, - }; - - for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++); - return tab->name; -} - -#endif /* notdef */ - -/* - * midisynth - */ - -int -midisynth_open(void *n, void *arg, int flags) -{ - struct snd_midi *m = ((struct synth_midi *)n)->m; - int retval; - - MIDI_DEBUG(1, printf("midisynth_open %s %s\n", - flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); - - if (m == NULL) - return ENXIO; - - mtx_lock(&m->lock); - mtx_lock(&m->qlock); - - retval = 0; - - if (flags & FREAD) { - if (MIDIQ_SIZE(m->inq) == 0) - retval = ENXIO; - else if (m->flags & M_RX) - retval = EBUSY; - if (retval) - goto err; - } - if (flags & FWRITE) { - if (MIDIQ_SIZE(m->outq) == 0) - retval = ENXIO; - else if (m->flags & M_TX) - retval = EBUSY; - if (retval) - goto err; - } - m->busy++; - - /* - * TODO: Consider m->async = 0; - */ - - if (flags & FREAD) { - m->flags |= M_RX | M_RXEN; - /* - * Only clear the inq, the outq might still have data to drain - * from a previous session - */ - MIDIQ_CLEAR(m->inq); - m->rchan = 0; - } - - if (flags & FWRITE) { - m->flags |= M_TX; - m->wchan = 0; - } - m->synth_flags = flags & (FREAD | FWRITE); - - MPU_CALLBACK(m, m->cookie, m->flags); - -err: mtx_unlock(&m->qlock); - mtx_unlock(&m->lock); - MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval)); - return retval; -} - -int -midisynth_close(void *n) -{ - struct snd_midi *m = ((struct synth_midi *)n)->m; - int retval; - int oldflags; - - MIDI_DEBUG(1, printf("midisynth_close %s %s\n", - m->synth_flags & FREAD ? "M_RX" : "", - m->synth_flags & FWRITE ? "M_TX" : "")); - - if (m == NULL) - return ENXIO; - - mtx_lock(&m->lock); - mtx_lock(&m->qlock); - - if ((m->synth_flags & FREAD && !(m->flags & M_RX)) || - (m->synth_flags & FWRITE && !(m->flags & M_TX))) { - retval = ENXIO; - goto err; - } - m->busy--; - - oldflags = m->flags; - - if (m->synth_flags & FREAD) - m->flags &= ~(M_RX | M_RXEN); - if (m->synth_flags & FWRITE) - m->flags &= ~M_TX; - - if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) - MPU_CALLBACK(m, m->cookie, m->flags); - - MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); - - mtx_unlock(&m->qlock); - mtx_unlock(&m->lock); - retval = 0; -err: return retval; -} - -/* - * Always blocking. - */ - -int -midisynth_writeraw(void *n, uint8_t *buf, size_t len) -{ - struct snd_midi *m = ((struct synth_midi *)n)->m; - int retval; - int used; - int i; - - MIDI_DEBUG(4, printf("midisynth_writeraw\n")); - - retval = 0; - - if (m == NULL) - return ENXIO; - - mtx_lock(&m->lock); - mtx_lock(&m->qlock); - - if (!(m->flags & M_TX)) - goto err1; - - if (midi_dumpraw) - printf("midi dump: "); - - while (len > 0) { - while (MIDIQ_AVAIL(m->outq) == 0) { - if (!(m->flags & M_TXEN)) { - m->flags |= M_TXEN; - MPU_CALLBACK(m, m->cookie, m->flags); - } - mtx_unlock(&m->lock); - m->wchan = 1; - MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n")); - retval = msleep(&m->wchan, &m->qlock, - PCATCH | PDROP, "midi TX", 0); - /* - * We slept, maybe things have changed since last - * dying check - */ - if (retval == EINTR) - goto err0; - - if (retval) - goto err0; - mtx_lock(&m->lock); - mtx_lock(&m->qlock); - m->wchan = 0; - if (!m->busy) - goto err1; - } - - /* - * We are certain than data can be placed on the queue - */ - - used = MIN(MIDIQ_AVAIL(m->outq), len); - used = MIN(used, MIDI_WSIZE); - MIDI_DEBUG(5, - printf("midi_synth: resid %zu len %jd avail %jd\n", - len, (intmax_t)MIDIQ_LEN(m->outq), - (intmax_t)MIDIQ_AVAIL(m->outq))); - - if (midi_dumpraw) - for (i = 0; i < used; i++) - printf("%x ", buf[i]); - - MIDIQ_ENQ(m->outq, buf, used); - len -= used; - - /* - * Inform the bottom half that data can be written - */ - if (!(m->flags & M_TXEN)) { - m->flags |= M_TXEN; - MPU_CALLBACK(m, m->cookie, m->flags); - } - } - /* - * If we Made it here then transfer is good - */ - if (midi_dumpraw) - printf("\n"); - - retval = 0; -err1: mtx_unlock(&m->qlock); - mtx_unlock(&m->lock); -err0: return retval; -} - -static int -midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) -{ - u_char c[3]; - - if (note > 127 || chn > 15) - return (EINVAL); - - if (vel > 127) - vel = 127; - - if (vel == 64) { - c[0] = 0x90 | (chn & 0x0f); /* Note on. */ - c[1] = (u_char)note; - c[2] = 0; - } else { - c[0] = 0x80 | (chn & 0x0f); /* Note off. */ - c[1] = (u_char)note; - c[2] = (u_char)vel; - } - - return midisynth_writeraw(n, c, 3); -} - -static int -midisynth_setinstr(void *n, uint8_t chn, uint16_t instr) -{ - u_char c[2]; - - if (instr > 127 || chn > 15) - return EINVAL; - - c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */ - c[1] = instr + midi_instroff; - - return midisynth_writeraw(n, c, 2); -} - -static int -midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) -{ - u_char c[3]; - - if (note > 127 || chn > 15) - return EINVAL; - - if (vel > 127) - vel = 127; - - c[0] = 0x90 | (chn & 0x0f); /* Note on. */ - c[1] = (u_char)note; - c[2] = (u_char)vel; - - return midisynth_writeraw(n, c, 3); -} -static int -midisynth_alloc(void *n, uint8_t chan, uint8_t note) -{ - return chan; -} - -static int -midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val) -{ - u_char c[3]; - - if (ctrlnum > 127 || chn > 15) - return EINVAL; - - c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ - c[1] = ctrlnum; - c[2] = val; - return midisynth_writeraw(n, c, 3); -} - -static int -midisynth_bender(void *n, uint8_t chn, uint16_t val) -{ - u_char c[3]; - - if (val > 16383 || chn > 15) - return EINVAL; - - c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ - c[1] = (u_char)val & 0x7f; - c[2] = (u_char)(val >> 7) & 0x7f; - - return midisynth_writeraw(n, c, 3); -} - -/* * Single point of midi destructions. */ static int @@ -1381,24 +817,16 @@ midi_destroy(struct snd_midi *m, int midiuninit) free(MIDIQ_BUF(m->outq), M_MIDI); mtx_destroy(&m->qlock); mtx_destroy(&m->lock); - free(m->synth, M_MIDI); free(m, M_MIDI); return 0; } -/* - * Load and unload functions, creates the /dev/midistat device - */ - static int midi_load(void) { sx_init(&mstat_lock, "midistat lock"); TAILQ_INIT(&midi_devs); - midistat_dev = make_dev(&midistat_cdevsw, MIDI_DEV_MIDICTL, UID_ROOT, - GID_WHEEL, 0666, "midistat"); - return 0; } @@ -1411,9 +839,6 @@ midi_unload(void) MIDI_DEBUG(1, printf("midi_unload()\n")); retval = EBUSY; midistat_lock(); - if (midistat_isopen) - goto exit0; - TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) { mtx_lock(&m->lock); if (m->busy) @@ -1421,28 +846,21 @@ midi_unload(void) else retval = midi_destroy(m, 1); if (retval) - goto exit1; + goto exit; } midistat_unlock(); - destroy_dev(midistat_dev); - /* - * Made it here then unload is complete - */ sx_destroy(&mstat_lock); return 0; -exit1: +exit: mtx_unlock(&m->lock); -exit0: midistat_unlock(); if (retval) MIDI_DEBUG(2, printf("midi_unload: failed\n")); return retval; } -extern int seq_modevent(module_t mod, int type, void *data); - static int midi_modevent(module_t mod, int type, void *data) { @@ -1453,14 +871,10 @@ midi_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: retval = midi_load(); - if (retval == 0) - retval = seq_modevent(mod, type, data); break; case MOD_UNLOAD: retval = midi_unload(); - if (retval == 0) - retval = seq_modevent(mod, type, data); break; default: @@ -1470,73 +884,5 @@ midi_modevent(module_t mod, int type, void *data) return retval; } -kobj_t -midimapper_addseq(void *arg1, int *unit, void **cookie) -{ - unit = NULL; - - return (kobj_t)arg1; -} - -int -midimapper_open_locked(void *arg1, void **cookie) -{ - int retval = 0; - struct snd_midi *m; - - midistat_lockassert(); - TAILQ_FOREACH(m, &midi_devs, link) { - retval++; - } - - return retval; -} - -int -midimapper_open(void *arg1, void **cookie) -{ - int retval; - - midistat_lock(); - retval = midimapper_open_locked(arg1, cookie); - midistat_unlock(); - - return retval; -} - -int -midimapper_close(void *arg1, void *cookie) -{ - return 0; -} - -kobj_t -midimapper_fetch_synth_locked(void *arg, void *cookie, int unit) -{ - struct snd_midi *m; - int retval = 0; - - midistat_lockassert(); - TAILQ_FOREACH(m, &midi_devs, link) { - if (unit == retval) - return (kobj_t)m->synth; - retval++; - } - - return NULL; -} - -kobj_t -midimapper_fetch_synth(void *arg, void *cookie, int unit) -{ - kobj_t synth; - - midistat_lock(); - synth = midimapper_fetch_synth_locked(arg, cookie, unit); - midistat_unlock(); - - return synth; -} - DEV_MODULE(midi, midi_modevent, NULL); MODULE_VERSION(midi, 1); diff --git a/sys/dev/sound/midi/midi.h b/sys/dev/sound/midi/midi.h index 2254fab690e9..286e84264ef3 100644 --- a/sys/dev/sound/midi/midi.h +++ b/sys/dev/sound/midi/midi.h @@ -51,11 +51,4 @@ int midi_uninit(struct snd_midi *_m); int midi_out(struct snd_midi *_m, uint8_t *_buf, int _size); int midi_in(struct snd_midi *_m, uint8_t *_buf, int _size); -kobj_t midimapper_addseq(void *arg1, int *unit, void **cookie); -int midimapper_open_locked(void *arg1, void **cookie); -int midimapper_open(void *arg1, void **cookie); -int midimapper_close(void *arg1, void *cookie); -kobj_t midimapper_fetch_synth_locked(void *arg, void *cookie, int unit); -kobj_t midimapper_fetch_synth(void *arg, void *cookie, int unit); - #endif diff --git a/sys/dev/sound/midi/mpu401.c b/sys/dev/sound/midi/mpu401.c index 2be285bc0040..224ebb1b01f4 100644 --- a/sys/dev/sound/midi/mpu401.c +++ b/sys/dev/sound/midi/mpu401.c @@ -88,8 +88,6 @@ static int mpu401_minqsize(struct snd_midi *, void *); static int mpu401_moutqsize(struct snd_midi *, void *); static void mpu401_mcallback(struct snd_midi *, void *, int); static void mpu401_mcallbackp(struct snd_midi *, void *, int); -static const char *mpu401_mdescr(struct snd_midi *, void *, int); -static const char *mpu401_mprovider(struct snd_midi *, void *); static kobj_method_t mpu401_methods[] = { KOBJMETHOD(mpu_init, mpu401_minit), @@ -98,8 +96,6 @@ static kobj_method_t mpu401_methods[] = { KOBJMETHOD(mpu_outqsize, mpu401_moutqsize), KOBJMETHOD(mpu_callback, mpu401_mcallback), KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp), - KOBJMETHOD(mpu_descr, mpu401_mdescr), - KOBJMETHOD(mpu_provider, mpu401_mprovider), KOBJMETHOD_END }; @@ -122,24 +118,12 @@ mpu401_intr(struct mpu401 *m) int i; int s; -/* - printf("mpu401_intr\n"); -*/ #define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0) #define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0) -#if 0 -#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"") -#else -#define D(x,l) -#endif i = 0; s = STATUS(m); - D(s, 1); while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) { b[i] = READ(m); -/* - printf("mpu401_intr in i %d d %d\n", i, b[i]); -*/ i++; s = STATUS(m); } @@ -148,15 +132,9 @@ mpu401_intr(struct mpu401 *m) i = 0; while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) { if (midi_out(m->mid, b, 1)) { -/* - printf("mpu401_intr out i %d d %d\n", i, b[0]); -*/ WRITE(m, *b); } else { -/* - printf("mpu401_intr write: no output\n"); -*/ return 0; } i++; @@ -262,13 +240,7 @@ static void mpu401_mcallback(struct snd_midi *sm, void *arg, int flags) { struct mpu401 *m = arg; -#if 0 - printf("mpu401_callback %s %s %s %s\n", - flags & M_RX ? "M_RX" : "", - flags & M_TX ? "M_TX" : "", - flags & M_RXEN ? "M_RXEN" : "", - flags & M_TXEN ? "M_TXEN" : ""); -#endif + if (flags & M_TXEN && m->si) { callout_reset(&m->timer, 1, mpu401_timeout, m); } @@ -278,19 +250,5 @@ mpu401_mcallback(struct snd_midi *sm, void *arg, int flags) static void mpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags) { -/* printf("mpu401_callbackp\n"); */ mpu401_mcallback(sm, arg, flags); } - -static const char * -mpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity) -{ - - return "descr mpu401"; -} - -static const char * -mpu401_mprovider(struct snd_midi *m, void *arg) -{ - return "provider mpu401"; -} diff --git a/sys/dev/sound/midi/mpu_if.m b/sys/dev/sound/midi/mpu_if.m index b7cb586c5dd0..835d887f703a 100644 --- a/sys/dev/sound/midi/mpu_if.m +++ b/sys/dev/sound/midi/mpu_if.m @@ -56,17 +56,6 @@ METHOD void callback { int _flags; }; -METHOD const char * provider { - struct snd_midi *_kobj; - void *_cookie; -}; - -METHOD const char * descr { - struct snd_midi *_kobj; - void *_cookie; - int _verbosity; -}; - METHOD int uninit { struct snd_midi *_kobj; void *_cookie; diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c deleted file mode 100644 index 03b71688175c..000000000000 --- a/sys/dev/sound/midi/sequencer.c +++ /dev/null @@ -1,2107 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2003 Mathew Kanner - * Copyright (c) 1993 Hannu Savolainen - * All rights reserved. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - */ - -/* - * The sequencer personality manager. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/ioccom.h> - -#include <sys/filio.h> -#include <sys/lock.h> -#include <sys/sockio.h> -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/sysctl.h> - -#include <sys/kernel.h> /* for DATA_SET */ - -#include <sys/module.h> -#include <sys/conf.h> -#include <sys/file.h> -#include <sys/uio.h> -#include <sys/syslog.h> -#include <sys/errno.h> -#include <sys/malloc.h> -#include <sys/bus.h> -#include <machine/resource.h> -#include <machine/bus.h> -#include <machine/clock.h> /* for DELAY */ -#include <sys/soundcard.h> -#include <sys/rman.h> -#include <sys/mman.h> -#include <sys/poll.h> -#include <sys/mutex.h> -#include <sys/condvar.h> -#include <sys/kthread.h> -#include <sys/unistd.h> -#include <sys/selinfo.h> -#include <sys/sx.h> - -#ifdef HAVE_KERNEL_OPTION_HEADERS -#include "opt_snd.h" -#endif - -#include <dev/sound/midi/midi.h> -#include <dev/sound/midi/midiq.h> -#include "synth_if.h" - -#include <dev/sound/midi/sequencer.h> - -#define TMR_TIMERBASE 13 - -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - * synthesizer and MIDI output) */ -#define SND_DEV_MUSIC 8 /* /dev/music, level 2 interface */ - -/* Length of a sequencer event. */ -#define EV_SZ 8 -#define IEV_SZ 8 - -/* Lookup modes */ -#define LOOKUP_EXIST (0) -#define LOOKUP_OPEN (1) -#define LOOKUP_CLOSE (2) - -#define MIDIDEV(y) (dev2unit(y) & 0x0f) - -/* These are the entries to the sequencer driver. */ -static d_open_t mseq_open; -static d_close_t mseq_close; -static d_ioctl_t mseq_ioctl; -static d_read_t mseq_read; -static d_write_t mseq_write; -static d_poll_t mseq_poll; - -static struct cdevsw seq_cdevsw = { - .d_version = D_VERSION, - .d_open = mseq_open, - .d_close = mseq_close, - .d_read = mseq_read, - .d_write = mseq_write, - .d_ioctl = mseq_ioctl, - .d_poll = mseq_poll, - .d_name = "sequencer", -}; - -struct seq_softc { - KOBJ_FIELDS; - - struct mtx seq_lock, q_lock; - struct cv empty_cv, reset_cv, in_cv, out_cv, state_cv, th_cv; - - MIDIQ_HEAD(, u_char) in_q, out_q; - - u_long flags; - /* Flags (protected by flag_mtx of mididev_info) */ - int fflags; /* Access mode */ - int music; - - int out_water; /* Sequence output threshould */ - snd_sync_parm sync_parm; /* AIOSYNC parameter set */ - struct thread *sync_thread; /* AIOSYNCing thread */ - struct selinfo in_sel, out_sel; - int midi_number; - struct cdev *seqdev, *musicdev; - int unit; - int maxunits; - kobj_t *midis; - int *midi_flags; - kobj_t mapper; - void *mapper_cookie; - struct timeval timerstop, timersub; - int timerbase, tempo; - int timerrun; - int done; - int playing; - int recording; - int busy; - int pre_event_timeout; - int waiting; -}; - -/* - * Module specific stuff, including how many sequecers - * we currently own. - */ - -SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, - "Midi sequencer"); - -int seq_debug; -/* XXX: should this be moved into debug.midi? */ -SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, ""); - -midi_cmdtab cmdtab_seqevent[] = { - {SEQ_NOTEOFF, "SEQ_NOTEOFF"}, - {SEQ_NOTEON, "SEQ_NOTEON"}, - {SEQ_WAIT, "SEQ_WAIT"}, - {SEQ_PGMCHANGE, "SEQ_PGMCHANGE"}, - {SEQ_SYNCTIMER, "SEQ_SYNCTIMER"}, - {SEQ_MIDIPUTC, "SEQ_MIDIPUTC"}, - {SEQ_DRUMON, "SEQ_DRUMON"}, - {SEQ_DRUMOFF, "SEQ_DRUMOFF"}, - {SEQ_ECHO, "SEQ_ECHO"}, - {SEQ_AFTERTOUCH, "SEQ_AFTERTOUCH"}, - {SEQ_CONTROLLER, "SEQ_CONTROLLER"}, - {SEQ_BALANCE, "SEQ_BALANCE"}, - {SEQ_VOLMODE, "SEQ_VOLMODE"}, - {SEQ_FULLSIZE, "SEQ_FULLSIZE"}, - {SEQ_PRIVATE, "SEQ_PRIVATE"}, - {SEQ_EXTENDED, "SEQ_EXTENDED"}, - {EV_SEQ_LOCAL, "EV_SEQ_LOCAL"}, - {EV_TIMING, "EV_TIMING"}, - {EV_CHN_COMMON, "EV_CHN_COMMON"}, - {EV_CHN_VOICE, "EV_CHN_VOICE"}, - {EV_SYSEX, "EV_SYSEX"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_seqioctl[] = { - {SNDCTL_SEQ_RESET, "SNDCTL_SEQ_RESET"}, - {SNDCTL_SEQ_SYNC, "SNDCTL_SEQ_SYNC"}, - {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"}, - {SNDCTL_SEQ_CTRLRATE, "SNDCTL_SEQ_CTRLRATE"}, - {SNDCTL_SEQ_GETOUTCOUNT, "SNDCTL_SEQ_GETOUTCOUNT"}, - {SNDCTL_SEQ_GETINCOUNT, "SNDCTL_SEQ_GETINCOUNT"}, - {SNDCTL_SEQ_PERCMODE, "SNDCTL_SEQ_PERCMODE"}, - {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"}, - {SNDCTL_SEQ_TESTMIDI, "SNDCTL_SEQ_TESTMIDI"}, - {SNDCTL_SEQ_RESETSAMPLES, "SNDCTL_SEQ_RESETSAMPLES"}, - {SNDCTL_SEQ_NRSYNTHS, "SNDCTL_SEQ_NRSYNTHS"}, - {SNDCTL_SEQ_NRMIDIS, "SNDCTL_SEQ_NRMIDIS"}, - {SNDCTL_SEQ_GETTIME, "SNDCTL_SEQ_GETTIME"}, - {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"}, - {SNDCTL_SEQ_THRESHOLD, "SNDCTL_SEQ_THRESHOLD"}, - {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"}, - {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"}, - {SNDCTL_PMGR_ACCESS, "SNDCTL_PMGR_ACCESS"}, - {SNDCTL_SEQ_PANIC, "SNDCTL_SEQ_PANIC"}, - {SNDCTL_SEQ_OUTOFBAND, "SNDCTL_SEQ_OUTOFBAND"}, - {SNDCTL_TMR_TIMEBASE, "SNDCTL_TMR_TIMEBASE"}, - {SNDCTL_TMR_START, "SNDCTL_TMR_START"}, - {SNDCTL_TMR_STOP, "SNDCTL_TMR_STOP"}, - {SNDCTL_TMR_CONTINUE, "SNDCTL_TMR_CONTINUE"}, - {SNDCTL_TMR_TEMPO, "SNDCTL_TMR_TEMPO"}, - {SNDCTL_TMR_SOURCE, "SNDCTL_TMR_SOURCE"}, - {SNDCTL_TMR_METRONOME, "SNDCTL_TMR_METRONOME"}, - {SNDCTL_TMR_SELECT, "SNDCTL_TMR_SELECT"}, - {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"}, - {AIONWRITE, "AIONWRITE"}, - {AIOGSIZE, "AIOGSIZE"}, - {AIOSSIZE, "AIOSSIZE"}, - {AIOGFMT, "AIOGFMT"}, - {AIOSFMT, "AIOSFMT"}, - {AIOGMIX, "AIOGMIX"}, - {AIOSMIX, "AIOSMIX"}, - {AIOSTOP, "AIOSTOP"}, - {AIOSYNC, "AIOSYNC"}, - {AIOGCAP, "AIOGCAP"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_timer[] = { - {TMR_WAIT_REL, "TMR_WAIT_REL"}, - {TMR_WAIT_ABS, "TMR_WAIT_ABS"}, - {TMR_STOP, "TMR_STOP"}, - {TMR_START, "TMR_START"}, - {TMR_CONTINUE, "TMR_CONTINUE"}, - {TMR_TEMPO, "TMR_TEMPO"}, - {TMR_ECHO, "TMR_ECHO"}, - {TMR_CLOCK, "TMR_CLOCK"}, - {TMR_SPP, "TMR_SPP"}, - {TMR_TIMESIG, "TMR_TIMESIG"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_seqcv[] = { - {MIDI_NOTEOFF, "MIDI_NOTEOFF"}, - {MIDI_NOTEON, "MIDI_NOTEON"}, - {MIDI_KEY_PRESSURE, "MIDI_KEY_PRESSURE"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_seqccmn[] = { - {MIDI_CTL_CHANGE, "MIDI_CTL_CHANGE"}, - {MIDI_PGM_CHANGE, "MIDI_PGM_CHANGE"}, - {MIDI_CHN_PRESSURE, "MIDI_CHN_PRESSURE"}, - {MIDI_PITCH_BEND, "MIDI_PITCH_BEND"}, - {MIDI_SYSTEM_PREFIX, "MIDI_SYSTEM_PREFIX"}, - {-1, NULL}, -}; - -#ifndef KOBJMETHOD_END -#define KOBJMETHOD_END { NULL, NULL } -#endif - -/* - * static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m); - */ - -static kobj_method_t seq_methods[] = { - /* KOBJMETHOD(mpu_provider,mpu401_mprovider), */ - KOBJMETHOD_END -}; - -DEFINE_CLASS(sequencer, seq_methods, 0); - -/* The followings are the local function. */ -static int seq_convertold(u_char *event, u_char *out); - -/* - * static void seq_midiinput(struct seq_softc * scp, void *md); - */ -static void seq_reset(struct seq_softc *scp); -static int seq_sync(struct seq_softc *scp); - -static int seq_processevent(struct seq_softc *scp, u_char *event); - -static int seq_timing(struct seq_softc *scp, u_char *event); -static int seq_local(struct seq_softc *scp, u_char *event); - -static int seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event); -static int seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event); -static int seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event); - -static int seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md); -void seq_copytoinput(struct seq_softc *scp, u_char *event, int len); -int seq_modevent(module_t mod, int type, void *data); -struct seq_softc *seqs[10]; -static struct mtx seqinfo_mtx; -static u_long nseq = 0; - -static void timer_start(struct seq_softc *t); -static void timer_stop(struct seq_softc *t); -static void timer_setvals(struct seq_softc *t, int tempo, int timerbase); -static void timer_wait(struct seq_softc *t, int ticks, int wait_abs); -static int timer_now(struct seq_softc *t); - -static void -timer_start(struct seq_softc *t) -{ - t->timerrun = 1; - getmicrotime(&t->timersub); -} - -static void -timer_continue(struct seq_softc *t) -{ - struct timeval now; - - if (t->timerrun == 1) - return; - t->timerrun = 1; - getmicrotime(&now); - timevalsub(&now, &t->timerstop); - timevaladd(&t->timersub, &now); -} - -static void -timer_stop(struct seq_softc *t) -{ - t->timerrun = 0; - getmicrotime(&t->timerstop); -} - -static void -timer_setvals(struct seq_softc *t, int tempo, int timerbase) -{ - t->tempo = tempo; - t->timerbase = timerbase; -} - -static void -timer_wait(struct seq_softc *t, int ticks, int wait_abs) -{ - struct timeval now, when; - int ret; - unsigned long long i; - - while (t->timerrun == 0) { - SEQ_DEBUG(2, printf("Timer wait when timer isn't running\n")); - /* - * The old sequencer used timeouts that only increased - * the timer when the timer was running. - * Hence the sequencer would stick (?) if the - * timer was disabled. - */ - cv_wait(&t->reset_cv, &t->seq_lock); - if (t->playing == 0) - return; - } - - i = ticks * 60ull * 1000000ull / (t->tempo * t->timerbase); - - when.tv_sec = i / 1000000; - when.tv_usec = i % 1000000; - -#if 0 - printf("timer_wait tempo %d timerbase %d ticks %d abs %d u_sec %llu\n", - t->tempo, t->timerbase, ticks, wait_abs, i); -#endif - - if (wait_abs != 0) { - getmicrotime(&now); - timevalsub(&now, &t->timersub); - timevalsub(&when, &now); - } - if (when.tv_sec < 0 || when.tv_usec < 0) { - SEQ_DEBUG(3, - printf("seq_timer error negative time %lds.%06lds\n", - (long)when.tv_sec, (long)when.tv_usec)); - return; - } - i = when.tv_sec * 1000000ull; - i += when.tv_usec; - i *= hz; - i /= 1000000ull; -#if 0 - printf("seq_timer usec %llu ticks %llu\n", - when.tv_sec * 1000000ull + when.tv_usec, i); -#endif - t->waiting = 1; - ret = cv_timedwait(&t->reset_cv, &t->seq_lock, i + 1); - t->waiting = 0; - - if (ret != EWOULDBLOCK) - SEQ_DEBUG(3, printf("seq_timer didn't timeout\n")); - -} - -static int -timer_now(struct seq_softc *t) -{ - struct timeval now; - unsigned long long i; - int ret; - - if (t->timerrun == 0) - now = t->timerstop; - else - getmicrotime(&now); - - timevalsub(&now, &t->timersub); - - i = now.tv_sec * 1000000ull; - i += now.tv_usec; - i *= t->timerbase; -/* i /= t->tempo; */ - i /= 1000000ull; - - ret = i; - /* - * printf("timer_now: %llu %d\n", i, ret); - */ - - return ret; -} - -static void -seq_eventthread(void *arg) -{ - struct seq_softc *scp = arg; - u_char event[EV_SZ]; - - mtx_lock(&scp->seq_lock); - SEQ_DEBUG(2, printf("seq_eventthread started\n")); - while (scp->done == 0) { -restart: - while (scp->playing == 0) { - cv_wait(&scp->state_cv, &scp->seq_lock); - if (scp->done) - goto done; - } - - while (MIDIQ_EMPTY(scp->out_q)) { - cv_broadcast(&scp->empty_cv); - cv_wait(&scp->out_cv, &scp->seq_lock); - if (scp->playing == 0) - goto restart; - if (scp->done) - goto done; - } - - MIDIQ_DEQ(scp->out_q, event, EV_SZ); - - if (MIDIQ_AVAIL(scp->out_q) < scp->out_water) { - cv_broadcast(&scp->out_cv); - selwakeup(&scp->out_sel); - } - seq_processevent(scp, event); - } - -done: - cv_broadcast(&scp->th_cv); - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(2, printf("seq_eventthread finished\n")); - kproc_exit(0); -} - -/* - * seq_processevent: This maybe called by the event thread or the IOCTL - * handler for queued and out of band events respectively. - */ -static int -seq_processevent(struct seq_softc *scp, u_char *event) -{ - int ret; - kobj_t m; - - ret = 0; - - if (event[0] == EV_SEQ_LOCAL) - ret = seq_local(scp, event); - else if (event[0] == EV_TIMING) - ret = seq_timing(scp, event); - else if (event[0] != EV_CHN_VOICE && - event[0] != EV_CHN_COMMON && - event[0] != EV_SYSEX && - event[0] != SEQ_MIDIPUTC) { - ret = 1; - SEQ_DEBUG(2, printf("seq_processevent not known %d\n", - event[0])); - } else if (seq_fetch_mid(scp, event[1], &m) != 0) { - ret = 1; - SEQ_DEBUG(2, printf("seq_processevent midi unit not found %d\n", - event[1])); - } else - switch (event[0]) { - case EV_CHN_VOICE: - ret = seq_chnvoice(scp, m, event); - break; - case EV_CHN_COMMON: - ret = seq_chncommon(scp, m, event); - break; - case EV_SYSEX: - ret = seq_sysex(scp, m, event); - break; - case SEQ_MIDIPUTC: - mtx_unlock(&scp->seq_lock); - ret = SYNTH_WRITERAW(m, &event[2], 1); - mtx_lock(&scp->seq_lock); - break; - } - return ret; -} - -static int -seq_addunit(void) -{ - struct seq_softc *scp; - int ret; - u_char *buf; - - gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer " - "needed or used\n"); - - /* Allocate the softc. */ - ret = ENOMEM; - scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO); - if (scp == NULL) { - SEQ_DEBUG(1, printf("seq_addunit: softc allocation failed.\n")); - goto err; - } - kobj_init((kobj_t)scp, &sequencer_class); - - buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO); - if (buf == NULL) - goto err; - MIDIQ_INIT(scp->in_q, buf, EV_SZ * 1024); - buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO); - if (buf == NULL) - goto err; - MIDIQ_INIT(scp->out_q, buf, EV_SZ * 1024); - ret = EINVAL; - - scp->midis = malloc(sizeof(kobj_t) * 32, M_TEMP, M_NOWAIT | M_ZERO); - scp->midi_flags = malloc(sizeof(*scp->midi_flags) * 32, M_TEMP, - M_NOWAIT | M_ZERO); - - if (scp->midis == NULL || scp->midi_flags == NULL) - goto err; - - scp->flags = 0; - - mtx_init(&scp->seq_lock, "seqflq", NULL, 0); - cv_init(&scp->state_cv, "seqstate"); - cv_init(&scp->empty_cv, "seqempty"); - cv_init(&scp->reset_cv, "seqtimer"); - cv_init(&scp->out_cv, "seqqout"); - cv_init(&scp->in_cv, "seqqin"); - cv_init(&scp->th_cv, "seqstart"); - - /* - * Init the damn timer - */ - - scp->mapper = midimapper_addseq(scp, &scp->unit, &scp->mapper_cookie); - if (scp->mapper == NULL) - goto err; - - scp->seqdev = make_dev(&seq_cdevsw, SND_DEV_SEQ, UID_ROOT, GID_WHEEL, - 0666, "sequencer%d", scp->unit); - - scp->musicdev = make_dev(&seq_cdevsw, SND_DEV_MUSIC, UID_ROOT, - GID_WHEEL, 0666, "music%d", scp->unit); - - if (scp->seqdev == NULL || scp->musicdev == NULL) - goto err; - /* - * TODO: Add to list of sequencers this module provides - */ - - ret = - kproc_create - (seq_eventthread, scp, NULL, RFHIGHPID, 0, - "sequencer %02d", scp->unit); - - if (ret) - goto err; - - scp->seqdev->si_drv1 = scp->musicdev->si_drv1 = scp; - - SEQ_DEBUG(2, printf("sequencer %d created scp %p\n", scp->unit, scp)); - - ret = 0; - - mtx_lock(&seqinfo_mtx); - seqs[nseq++] = scp; - mtx_unlock(&seqinfo_mtx); - - goto ok; - -err: - if (scp != NULL) { - if (scp->seqdev != NULL) - destroy_dev(scp->seqdev); - if (scp->musicdev != NULL) - destroy_dev(scp->musicdev); - /* - * TODO: Destroy mutex and cv - */ - if (scp->midis != NULL) - free(scp->midis, M_TEMP); - if (scp->midi_flags != NULL) - free(scp->midi_flags, M_TEMP); - if (scp->out_q.b) - free(scp->out_q.b, M_TEMP); - if (scp->in_q.b) - free(scp->in_q.b, M_TEMP); - free(scp, M_DEVBUF); - } -ok: - return ret; -} - -static int -seq_delunit(int unit) -{ - struct seq_softc *scp = seqs[unit]; - int i; - - //SEQ_DEBUG(4, printf("seq_delunit: %d\n", unit)); - SEQ_DEBUG(1, printf("seq_delunit: 1 \n")); - mtx_lock(&scp->seq_lock); - - scp->playing = 0; - scp->done = 1; - cv_broadcast(&scp->out_cv); - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->reset_cv); - SEQ_DEBUG(1, printf("seq_delunit: 2 \n")); - cv_wait(&scp->th_cv, &scp->seq_lock); - SEQ_DEBUG(1, printf("seq_delunit: 3.0 \n")); - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(1, printf("seq_delunit: 3.1 \n")); - - cv_destroy(&scp->state_cv); - SEQ_DEBUG(1, printf("seq_delunit: 4 \n")); - cv_destroy(&scp->empty_cv); - SEQ_DEBUG(1, printf("seq_delunit: 5 \n")); - cv_destroy(&scp->reset_cv); - SEQ_DEBUG(1, printf("seq_delunit: 6 \n")); - cv_destroy(&scp->out_cv); - SEQ_DEBUG(1, printf("seq_delunit: 7 \n")); - cv_destroy(&scp->in_cv); - SEQ_DEBUG(1, printf("seq_delunit: 8 \n")); - cv_destroy(&scp->th_cv); - - SEQ_DEBUG(1, printf("seq_delunit: 10 \n")); - if (scp->seqdev) - destroy_dev(scp->seqdev); - SEQ_DEBUG(1, printf("seq_delunit: 11 \n")); - if (scp->musicdev) - destroy_dev(scp->musicdev); - SEQ_DEBUG(1, printf("seq_delunit: 12 \n")); - scp->seqdev = scp->musicdev = NULL; - if (scp->midis != NULL) - free(scp->midis, M_TEMP); - SEQ_DEBUG(1, printf("seq_delunit: 13 \n")); - if (scp->midi_flags != NULL) - free(scp->midi_flags, M_TEMP); - SEQ_DEBUG(1, printf("seq_delunit: 14 \n")); - free(scp->out_q.b, M_TEMP); - SEQ_DEBUG(1, printf("seq_delunit: 15 \n")); - free(scp->in_q.b, M_TEMP); - - SEQ_DEBUG(1, printf("seq_delunit: 16 \n")); - - mtx_destroy(&scp->seq_lock); - SEQ_DEBUG(1, printf("seq_delunit: 17 \n")); - free(scp, M_DEVBUF); - - mtx_lock(&seqinfo_mtx); - for (i = unit; i < (nseq - 1); i++) - seqs[i] = seqs[i + 1]; - nseq--; - mtx_unlock(&seqinfo_mtx); - - return 0; -} - -int -seq_modevent(module_t mod, int type, void *data) -{ - int retval, r; - - retval = 0; - - switch (type) { - case MOD_LOAD: - mtx_init(&seqinfo_mtx, "seqmod", NULL, 0); - retval = seq_addunit(); - break; - - case MOD_UNLOAD: - while (nseq) { - r = seq_delunit(nseq - 1); - if (r) { - retval = r; - break; - } - } - if (nseq == 0) { - retval = 0; - mtx_destroy(&seqinfo_mtx); - } - break; - - default: - break; - } - - return retval; -} - -static int -seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md) -{ - - if (unit >= scp->midi_number || unit < 0) - return EINVAL; - - *md = scp->midis[unit]; - - return 0; -} - -int -mseq_open(struct cdev *i_dev, int flags, int mode, struct thread *td) -{ - struct seq_softc *scp = i_dev->si_drv1; - int i; - - gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer " - "needed or used\n"); - - if (scp == NULL) - return ENXIO; - - SEQ_DEBUG(3, printf("seq_open: scp %p unit %d, flags 0x%x.\n", - scp, scp->unit, flags)); - - /* - * Mark this device busy. - */ - - midistat_lock(); - mtx_lock(&scp->seq_lock); - if (scp->busy) { - mtx_unlock(&scp->seq_lock); - midistat_unlock(); - SEQ_DEBUG(2, printf("seq_open: unit %d is busy.\n", scp->unit)); - return EBUSY; - } - scp->fflags = flags; - /* - if ((scp->fflags & O_NONBLOCK) != 0) - scp->flags |= SEQ_F_NBIO; - */ - scp->music = MIDIDEV(i_dev) == SND_DEV_MUSIC; - - /* - * Enumerate the available midi devices - */ - scp->midi_number = 0; - scp->maxunits = midimapper_open_locked(scp->mapper, &scp->mapper_cookie); - - if (scp->maxunits == 0) - SEQ_DEBUG(2, printf("seq_open: no midi devices\n")); - - for (i = 0; i < scp->maxunits; i++) { - scp->midis[scp->midi_number] = - midimapper_fetch_synth_locked(scp->mapper, - scp->mapper_cookie, i); - if (scp->midis[scp->midi_number]) { - if (SYNTH_OPEN(scp->midis[scp->midi_number], scp, - scp->fflags) != 0) - scp->midis[scp->midi_number] = NULL; - else { - scp->midi_flags[scp->midi_number] = - SYNTH_QUERY(scp->midis[scp->midi_number]); - scp->midi_number++; - } - } - } - midistat_unlock(); - - timer_setvals(scp, 60, 100); - - timer_start(scp); - timer_stop(scp); - /* - * actually, if we're in rdonly mode, we should start the timer - */ - /* - * TODO: Handle recording now - */ - - scp->out_water = MIDIQ_SIZE(scp->out_q) / 2; - - scp->busy = 1; - mtx_unlock(&scp->seq_lock); - - SEQ_DEBUG(2, printf("seq_open: opened, mode %s.\n", - scp->music ? "music" : "sequencer")); - SEQ_DEBUG(2, - printf("Sequencer %d %p opened maxunits %d midi_number %d:\n", - scp->unit, scp, scp->maxunits, scp->midi_number)); - for (i = 0; i < scp->midi_number; i++) - SEQ_DEBUG(3, printf(" midi %d %p\n", i, scp->midis[i])); - - return 0; -} - -/* - * mseq_close - */ -int -mseq_close(struct cdev *i_dev, int flags, int mode, struct thread *td) -{ - int i; - struct seq_softc *scp = i_dev->si_drv1; - int ret; - - if (scp == NULL) - return ENXIO; - - SEQ_DEBUG(2, printf("seq_close: unit %d.\n", scp->unit)); - - mtx_lock(&scp->seq_lock); - - ret = ENXIO; - if (scp->busy == 0) - goto err; - - seq_reset(scp); - seq_sync(scp); - - for (i = 0; i < scp->midi_number; i++) - if (scp->midis[i]) - SYNTH_CLOSE(scp->midis[i]); - - midimapper_close(scp->mapper, scp->mapper_cookie); - - timer_stop(scp); - - scp->busy = 0; - ret = 0; - -err: - SEQ_DEBUG(3, printf("seq_close: closed ret = %d.\n", ret)); - mtx_unlock(&scp->seq_lock); - return ret; -} - -int -mseq_read(struct cdev *i_dev, struct uio *uio, int ioflag) -{ - int retval, used; - struct seq_softc *scp = i_dev->si_drv1; - -#define SEQ_RSIZE 32 - u_char buf[SEQ_RSIZE]; - - if (scp == NULL) - return ENXIO; - - SEQ_DEBUG(7, printf("mseq_read: unit %d, resid %zd.\n", - scp->unit, uio->uio_resid)); - - mtx_lock(&scp->seq_lock); - if ((scp->fflags & FREAD) == 0) { - SEQ_DEBUG(2, printf("mseq_read: unit %d is not for reading.\n", - scp->unit)); - retval = EIO; - goto err1; - } - /* - * Begin recording. - */ - /* - * if ((scp->flags & SEQ_F_READING) == 0) - */ - /* - * TODO, start recording if not alread - */ - - /* - * I think the semantics are to return as soon - * as possible. - * Second thought, it doesn't seem like midimoutain - * expects that at all. - * TODO: Look up in some sort of spec - */ - - while (uio->uio_resid > 0) { - while (MIDIQ_EMPTY(scp->in_q)) { - retval = EWOULDBLOCK; - /* - * I wish I knew which one to care about - */ - - if (scp->fflags & O_NONBLOCK) - goto err1; - if (ioflag & O_NONBLOCK) - goto err1; - - retval = cv_wait_sig(&scp->in_cv, &scp->seq_lock); - if (retval != 0) - goto err1; - } - - used = MIN(MIDIQ_LEN(scp->in_q), uio->uio_resid); - used = MIN(used, SEQ_RSIZE); - - SEQ_DEBUG(8, printf("midiread: uiomove cc=%d\n", used)); - MIDIQ_DEQ(scp->in_q, buf, used); - mtx_unlock(&scp->seq_lock); - retval = uiomove(buf, used, uio); - mtx_lock(&scp->seq_lock); - if (retval) - goto err1; - } - - retval = 0; -err1: - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(6, printf("mseq_read: ret %d, resid %zd.\n", - retval, uio->uio_resid)); - - return retval; -} - -int -mseq_write(struct cdev *i_dev, struct uio *uio, int ioflag) -{ - u_char event[EV_SZ], newevent[EV_SZ], ev_code; - struct seq_softc *scp = i_dev->si_drv1; - int retval; - int used; - - SEQ_DEBUG(7, printf("seq_write: unit %d, resid %zd.\n", - scp->unit, uio->uio_resid)); - - if (scp == NULL) - return ENXIO; - - mtx_lock(&scp->seq_lock); - - if ((scp->fflags & FWRITE) == 0) { - SEQ_DEBUG(2, printf("seq_write: unit %d is not for writing.\n", - scp->unit)); - retval = EIO; - goto err0; - } - while (uio->uio_resid > 0) { - while (MIDIQ_AVAIL(scp->out_q) == 0) { - retval = EWOULDBLOCK; - if (scp->fflags & O_NONBLOCK) - goto err0; - if (ioflag & O_NONBLOCK) - goto err0; - SEQ_DEBUG(8, printf("seq_write cvwait\n")); - - scp->playing = 1; - cv_broadcast(&scp->out_cv); - cv_broadcast(&scp->state_cv); - - retval = cv_wait_sig(&scp->out_cv, &scp->seq_lock); - /* - * We slept, maybe things have changed since last - * dying check - */ - if (retval != 0) - goto err0; -#if 0 - /* - * Useless test - */ - if (scp != i_dev->si_drv1) - retval = ENXIO; -#endif - } - - used = MIN(uio->uio_resid, 4); - - SEQ_DEBUG(8, printf("seqout: resid %zd len %jd avail %jd\n", - uio->uio_resid, (intmax_t)MIDIQ_LEN(scp->out_q), - (intmax_t)MIDIQ_AVAIL(scp->out_q))); - - if (used != 4) { - retval = ENXIO; - goto err0; - } - mtx_unlock(&scp->seq_lock); - retval = uiomove(event, used, uio); - mtx_lock(&scp->seq_lock); - if (retval) - goto err0; - - ev_code = event[0]; - SEQ_DEBUG(8, printf("seq_write: unit %d, event %s.\n", - scp->unit, midi_cmdname(ev_code, cmdtab_seqevent))); - - /* Have a look at the event code. */ - if (ev_code == SEQ_FULLSIZE) { - /* - * TODO: restore code for SEQ_FULLSIZE - */ -#if 0 - /* - * A long event, these are the patches/samples for a - * synthesizer. - */ - midiunit = *(u_short *)&event[2]; - mtx_lock(&sd->seq_lock); - ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->seq_lock); - if (ret != 0) - return (ret); - - SEQ_DEBUG(printf("seq_write: loading a patch to the unit %d.\n", midiunit)); - - ret = md->synth.loadpatch(md, *(short *)&event[0], buf, - p + 4, count, 0); - return (ret); -#else - /* - * For now, just flush the darn buffer - */ - SEQ_DEBUG(2, - printf("seq_write: SEQ_FULLSIZE flusing buffer.\n")); - while (uio->uio_resid > 0) { - mtx_unlock(&scp->seq_lock); - retval = uiomove(event, MIN(EV_SZ, uio->uio_resid), uio); - mtx_lock(&scp->seq_lock); - if (retval) - goto err0; - } - retval = 0; - goto err0; -#endif - } - retval = EINVAL; - if (ev_code >= 128) { - int error; - - /* - * Some sort of an extended event. The size is eight - * bytes. scoop extra info. - */ - if (scp->music && ev_code == SEQ_EXTENDED) { - SEQ_DEBUG(2, printf("seq_write: invalid level two event %x.\n", ev_code)); - goto err0; - } - mtx_unlock(&scp->seq_lock); - if (uio->uio_resid < 4) - error = EINVAL; - else - error = uiomove((caddr_t)&event[4], 4, uio); - mtx_lock(&scp->seq_lock); - if (error) { - SEQ_DEBUG(2, - printf("seq_write: user memory mangled?\n")); - goto err0; - } - } else { - /* - * Size four event. - */ - if (scp->music) { - SEQ_DEBUG(2, printf("seq_write: four byte event in music mode.\n")); - goto err0; - } - } - if (ev_code == SEQ_MIDIPUTC) { - /* - * TODO: event[2] is unit number to receive char. - * Range check it. - */ - } - if (scp->music) { -#ifdef not_ever_ever - if (event[0] == EV_TIMING && - (event[1] == TMR_START || event[1] == TMR_STOP)) { - /* - * For now, try to make midimoutain work by - * forcing these events to be processed - * immediately. - */ - seq_processevent(scp, event); - } else - MIDIQ_ENQ(scp->out_q, event, EV_SZ); -#else - MIDIQ_ENQ(scp->out_q, event, EV_SZ); -#endif - } else { - if (seq_convertold(event, newevent) > 0) - MIDIQ_ENQ(scp->out_q, newevent, EV_SZ); -#if 0 - else - goto err0; -#endif - } - } - - scp->playing = 1; - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->out_cv); - - retval = 0; - -err0: - SEQ_DEBUG(6, - printf("seq_write done: leftover buffer length %zd retval %d\n", - uio->uio_resid, retval)); - mtx_unlock(&scp->seq_lock); - return retval; -} - -int -mseq_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, - struct thread *td) -{ - int midiunit, ret, tmp; - struct seq_softc *scp = i_dev->si_drv1; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - u_char event[EV_SZ]; - u_char newevent[EV_SZ]; - - kobj_t md; - - /* - * struct snd_size *sndsize; - */ - - if (scp == NULL) - return ENXIO; - - SEQ_DEBUG(6, printf("seq_ioctl: unit %d, cmd %s.\n", - scp->unit, midi_cmdname(cmd, cmdtab_seqioctl))); - - ret = 0; - - switch (cmd) { - case SNDCTL_SEQ_GETTIME: - /* - * ioctl needed by libtse - */ - mtx_lock(&scp->seq_lock); - *(int *)arg = timer_now(scp); - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(6, printf("seq_ioctl: gettime %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_TMR_METRONOME: - /* fallthrough */ - case SNDCTL_TMR_SOURCE: - /* - * Not implemented - */ - ret = 0; - break; - case SNDCTL_TMR_TEMPO: - event[1] = TMR_TEMPO; - event[4] = *(int *)arg & 0xFF; - event[5] = (*(int *)arg >> 8) & 0xFF; - event[6] = (*(int *)arg >> 16) & 0xFF; - event[7] = (*(int *)arg >> 24) & 0xFF; - goto timerevent; - case SNDCTL_TMR_TIMEBASE: - event[1] = TMR_TIMERBASE; - event[4] = *(int *)arg & 0xFF; - event[5] = (*(int *)arg >> 8) & 0xFF; - event[6] = (*(int *)arg >> 16) & 0xFF; - event[7] = (*(int *)arg >> 24) & 0xFF; - goto timerevent; - case SNDCTL_TMR_START: - event[1] = TMR_START; - goto timerevent; - case SNDCTL_TMR_STOP: - event[1] = TMR_STOP; - goto timerevent; - case SNDCTL_TMR_CONTINUE: - event[1] = TMR_CONTINUE; -timerevent: - event[0] = EV_TIMING; - mtx_lock(&scp->seq_lock); - if (!scp->music) { - ret = EINVAL; - mtx_unlock(&scp->seq_lock); - break; - } - seq_processevent(scp, event); - mtx_unlock(&scp->seq_lock); - break; - case SNDCTL_TMR_SELECT: - SEQ_DEBUG(2, - printf("seq_ioctl: SNDCTL_TMR_SELECT not supported\n")); - ret = EINVAL; - break; - case SNDCTL_SEQ_SYNC: - if (mode == O_RDONLY) { - ret = 0; - break; - } - mtx_lock(&scp->seq_lock); - ret = seq_sync(scp); - mtx_unlock(&scp->seq_lock); - break; - case SNDCTL_SEQ_PANIC: - /* fallthrough */ - case SNDCTL_SEQ_RESET: - /* - * SNDCTL_SEQ_PANIC == SNDCTL_SEQ_RESET - */ - mtx_lock(&scp->seq_lock); - seq_reset(scp); - mtx_unlock(&scp->seq_lock); - ret = 0; - break; - case SNDCTL_SEQ_TESTMIDI: - mtx_lock(&scp->seq_lock); - /* - * TODO: SNDCTL_SEQ_TESTMIDI now means "can I write to the - * device?". - */ - mtx_unlock(&scp->seq_lock); - break; -#if 0 - case SNDCTL_SEQ_GETINCOUNT: - if (mode == O_WRONLY) - *(int *)arg = 0; - else { - mtx_lock(&scp->seq_lock); - *(int *)arg = scp->in_q.rl; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(printf("seq_ioctl: incount %d.\n", - *(int *)arg)); - } - ret = 0; - break; - case SNDCTL_SEQ_GETOUTCOUNT: - if (mode == O_RDONLY) - *(int *)arg = 0; - else { - mtx_lock(&scp->seq_lock); - *(int *)arg = scp->out_q.fl; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(printf("seq_ioctl: outcount %d.\n", - *(int *)arg)); - } - ret = 0; - break; -#endif - case SNDCTL_SEQ_CTRLRATE: - if (*(int *)arg != 0) { - ret = EINVAL; - break; - } - mtx_lock(&scp->seq_lock); - *(int *)arg = scp->timerbase; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(3, printf("seq_ioctl: ctrlrate %d.\n", *(int *)arg)); - ret = 0; - break; - /* - * TODO: ioctl SNDCTL_SEQ_RESETSAMPLES - */ -#if 0 - case SNDCTL_SEQ_RESETSAMPLES: - mtx_lock(&scp->seq_lock); - ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&scp->seq_lock); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg, - SND_DEV_MIDIN), cmd, arg, mode, td); - break; -#endif - case SNDCTL_SEQ_NRSYNTHS: - mtx_lock(&scp->seq_lock); - *(int *)arg = scp->midi_number; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(3, printf("seq_ioctl: synths %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_SEQ_NRMIDIS: - mtx_lock(&scp->seq_lock); - if (scp->music) - *(int *)arg = 0; - else { - /* - * TODO: count the numbder of devices that can WRITERAW - */ - *(int *)arg = scp->midi_number; - } - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(3, printf("seq_ioctl: midis %d.\n", *(int *)arg)); - ret = 0; - break; - /* - * TODO: ioctl SNDCTL_SYNTH_MEMAVL - */ -#if 0 - case SNDCTL_SYNTH_MEMAVL: - mtx_lock(&scp->seq_lock); - ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&scp->seq_lock); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg, - SND_DEV_MIDIN), cmd, arg, mode, td); - break; -#endif - case SNDCTL_SEQ_OUTOFBAND: - for (ret = 0; ret < EV_SZ; ret++) - event[ret] = (u_char)arg[0]; - - mtx_lock(&scp->seq_lock); - if (scp->music) - ret = seq_processevent(scp, event); - else { - if (seq_convertold(event, newevent) > 0) - ret = seq_processevent(scp, newevent); - else - ret = EINVAL; - } - mtx_unlock(&scp->seq_lock); - break; - case SNDCTL_SYNTH_INFO: - synthinfo = (struct synth_info *)arg; - midiunit = synthinfo->device; - mtx_lock(&scp->seq_lock); - if (seq_fetch_mid(scp, midiunit, &md) == 0) { - bzero(synthinfo, sizeof(*synthinfo)); - synthinfo->name[0] = 'f'; - synthinfo->name[1] = 'a'; - synthinfo->name[2] = 'k'; - synthinfo->name[3] = 'e'; - synthinfo->name[4] = 's'; - synthinfo->name[5] = 'y'; - synthinfo->name[6] = 'n'; - synthinfo->name[7] = 't'; - synthinfo->name[8] = 'h'; - synthinfo->device = midiunit; - synthinfo->synth_type = SYNTH_TYPE_MIDI; - synthinfo->capabilities = scp->midi_flags[midiunit]; - ret = 0; - } else - ret = EINVAL; - mtx_unlock(&scp->seq_lock); - break; - case SNDCTL_MIDI_INFO: - midiinfo = (struct midi_info *)arg; - midiunit = midiinfo->device; - mtx_lock(&scp->seq_lock); - if (seq_fetch_mid(scp, midiunit, &md) == 0) { - bzero(midiinfo, sizeof(*midiinfo)); - midiinfo->name[0] = 'f'; - midiinfo->name[1] = 'a'; - midiinfo->name[2] = 'k'; - midiinfo->name[3] = 'e'; - midiinfo->name[4] = 'm'; - midiinfo->name[5] = 'i'; - midiinfo->name[6] = 'd'; - midiinfo->name[7] = 'i'; - midiinfo->device = midiunit; - midiinfo->capabilities = scp->midi_flags[midiunit]; - /* - * TODO: What devtype? - */ - midiinfo->dev_type = 0x01; - ret = 0; - } else - ret = EINVAL; - mtx_unlock(&scp->seq_lock); - break; - case SNDCTL_SEQ_THRESHOLD: - mtx_lock(&scp->seq_lock); - RANGE(*(int *)arg, 1, MIDIQ_SIZE(scp->out_q) - 1); - scp->out_water = *(int *)arg; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(3, printf("seq_ioctl: water %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_MIDI_PRETIME: - tmp = *(int *)arg; - if (tmp < 0) - tmp = 0; - mtx_lock(&scp->seq_lock); - scp->pre_event_timeout = (hz * tmp) / 10; - *(int *)arg = scp->pre_event_timeout; - mtx_unlock(&scp->seq_lock); - SEQ_DEBUG(3, printf("seq_ioctl: pretime %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_FM_4OP_ENABLE: - case SNDCTL_PMGR_IFACE: - case SNDCTL_PMGR_ACCESS: - /* - * Patch manager and fm are ded, ded, ded. - */ - /* fallthrough */ - default: - /* - * TODO: Consider ioctl default case. - * Old code used to - * if ((scp->fflags & O_ACCMODE) == FREAD) { - * ret = EIO; - * break; - * } - * Then pass on the ioctl to device 0 - */ - SEQ_DEBUG(2, - printf("seq_ioctl: unsupported IOCTL %ld.\n", cmd)); - ret = EINVAL; - break; - } - - return ret; -} - -int -mseq_poll(struct cdev *i_dev, int events, struct thread *td) -{ - int ret, lim; - struct seq_softc *scp = i_dev->si_drv1; - - SEQ_DEBUG(3, printf("seq_poll: unit %d.\n", scp->unit)); - SEQ_DEBUG(1, printf("seq_poll: unit %d.\n", scp->unit)); - - mtx_lock(&scp->seq_lock); - - ret = 0; - - /* Look up the appropriate queue and select it. */ - if ((events & (POLLOUT | POLLWRNORM)) != 0) { - /* Start playing. */ - scp->playing = 1; - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->out_cv); - - lim = scp->out_water; - - if (MIDIQ_AVAIL(scp->out_q) < lim) - /* No enough space, record select. */ - selrecord(td, &scp->out_sel); - else - /* We can write now. */ - ret |= events & (POLLOUT | POLLWRNORM); - } - if ((events & (POLLIN | POLLRDNORM)) != 0) { - /* TODO: Start recording. */ - - /* Find out the boundary. */ - lim = 1; - if (MIDIQ_LEN(scp->in_q) < lim) - /* No data ready, record select. */ - selrecord(td, &scp->in_sel); - else - /* We can read now. */ - ret |= events & (POLLIN | POLLRDNORM); - } - mtx_unlock(&scp->seq_lock); - - return (ret); -} - -#if 0 -static void -sein_qtr(void *p, void /* mididev_info */ *md) -{ - struct seq_softc *scp; - - scp = (struct seq_softc *)p; - - mtx_lock(&scp->seq_lock); - - /* Restart playing if we have the data to output. */ - if (scp->queueout_pending) - seq_callback(scp, SEQ_CB_START | SEQ_CB_WR); - /* Check the midi device if we are reading. */ - if ((scp->flags & SEQ_F_READING) != 0) - seq_midiinput(scp, md); - - mtx_unlock(&scp->seq_lock); -} - -#endif -/* - * seq_convertold - * Was the old playevent. Use this to convert and old - * style /dev/sequencer event to a /dev/music event - */ -static int -seq_convertold(u_char *event, u_char *out) -{ - int used; - u_char dev, chn, note, vel; - - out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = - out[7] = 0; - - dev = 0; - chn = event[1]; - note = event[2]; - vel = event[3]; - - used = 0; - -restart: - /* - * TODO: Debug statement - */ - switch (event[0]) { - case EV_TIMING: - case EV_CHN_VOICE: - case EV_CHN_COMMON: - case EV_SYSEX: - case EV_SEQ_LOCAL: - out[0] = event[0]; - out[1] = event[1]; - out[2] = event[2]; - out[3] = event[3]; - out[4] = event[4]; - out[5] = event[5]; - out[6] = event[6]; - out[7] = event[7]; - used += 8; - break; - case SEQ_NOTEOFF: - out[0] = EV_CHN_VOICE; - out[1] = dev; - out[2] = MIDI_NOTEOFF; - out[3] = chn; - out[4] = note; - out[5] = 255; - used += 4; - break; - - case SEQ_NOTEON: - out[0] = EV_CHN_VOICE; - out[1] = dev; - out[2] = MIDI_NOTEON; - out[3] = chn; - out[4] = note; - out[5] = vel; - used += 4; - break; - - /* - * wait delay = (event[2] << 16) + (event[3] << 8) + event[4] - */ - - case SEQ_PGMCHANGE: - out[0] = EV_CHN_COMMON; - out[1] = dev; - out[2] = MIDI_PGM_CHANGE; - out[3] = chn; - out[4] = note; - out[5] = vel; - used += 4; - break; -/* - out[0] = EV_TIMING; - out[1] = dev; - out[2] = MIDI_PGM_CHANGE; - out[3] = chn; - out[4] = note; - out[5] = vel; - SEQ_DEBUG(4,printf("seq_playevent: synctimer\n")); - break; -*/ - - case SEQ_MIDIPUTC: - SEQ_DEBUG(4, - printf("seq_playevent: put data 0x%02x, unit %d.\n", - event[1], event[2])); - /* - * Pass through to the midi device. - * device = event[2] - * data = event[1] - */ - out[0] = SEQ_MIDIPUTC; - out[1] = dev; - out[2] = chn; - used += 4; - break; -#ifdef notyet - case SEQ_ECHO: - /* - * This isn't handled here yet because I don't know if I can - * just use four bytes events. There might be consequences - * in the _read routing - */ - if (seq_copytoinput(scp, event, 4) == EAGAIN) { - ret = QUEUEFULL; - break; - } - ret = MORE; - break; -#endif - case SEQ_EXTENDED: - switch (event[1]) { - case SEQ_NOTEOFF: - case SEQ_NOTEON: - case SEQ_PGMCHANGE: - event++; - used = 4; - goto restart; - break; - case SEQ_AFTERTOUCH: - /* - * SYNTH_AFTERTOUCH(md, event[3], event[4]) - */ - case SEQ_BALANCE: - /* - * SYNTH_PANNING(md, event[3], (char)event[4]) - */ - case SEQ_CONTROLLER: - /* - * SYNTH_CONTROLLER(md, event[3], event[4], *(short *)&event[5]) - */ - case SEQ_VOLMODE: - /* - * SYNTH_VOLUMEMETHOD(md, event[3]) - */ - default: - SEQ_DEBUG(2, - printf("seq_convertold: SEQ_EXTENDED type %d" - "not handled\n", event[1])); - break; - } - break; - case SEQ_WAIT: - out[0] = EV_TIMING; - out[1] = TMR_WAIT_REL; - out[4] = event[2]; - out[5] = event[3]; - out[6] = event[4]; - - SEQ_DEBUG(5, printf("SEQ_WAIT %d", - event[2] + (event[3] << 8) + (event[4] << 24))); - - used += 4; - break; - - case SEQ_ECHO: - case SEQ_SYNCTIMER: - case SEQ_PRIVATE: - default: - SEQ_DEBUG(2, - printf("seq_convertold: event type %d not handled %d %d %d\n", - event[0], event[1], event[2], event[3])); - break; - } - return used; -} - -/* - * Writting to the sequencer buffer never blocks and drops - * input which cannot be queued - */ -void -seq_copytoinput(struct seq_softc *scp, u_char *event, int len) -{ - - mtx_assert(&scp->seq_lock, MA_OWNED); - - if (MIDIQ_AVAIL(scp->in_q) < len) { - /* - * ENOROOM? EINPUTDROPPED? ETOUGHLUCK? - */ - SEQ_DEBUG(2, printf("seq_copytoinput: queue full\n")); - } else { - MIDIQ_ENQ(scp->in_q, event, len); - selwakeup(&scp->in_sel); - cv_broadcast(&scp->in_cv); - } - -} - -static int -seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event) -{ - int ret, voice; - u_char cmd, chn, note, parm; - - ret = 0; - cmd = event[2]; - chn = event[3]; - note = event[4]; - parm = event[5]; - - mtx_assert(&scp->seq_lock, MA_OWNED); - - SEQ_DEBUG(5, printf("seq_chnvoice: unit %d, dev %d, cmd %s," - " chn %d, note %d, parm %d.\n", scp->unit, event[1], - midi_cmdname(cmd, cmdtab_seqcv), chn, note, parm)); - - voice = SYNTH_ALLOC(md, chn, note); - - mtx_unlock(&scp->seq_lock); - - switch (cmd) { - case MIDI_NOTEON: - if (note < 128 || note == 255) { -#if 0 - if (scp->music && chn == 9) { - /* - * This channel is a percussion. The note - * number is the patch number. - */ - /* - mtx_unlock(&scp->seq_lock); - if (SYNTH_SETINSTR(md, voice, 128 + note) - == EAGAIN) { - mtx_lock(&scp->seq_lock); - return (QUEUEFULL); - } - mtx_lock(&scp->seq_lock); - */ - note = 60; /* Middle C. */ - } -#endif - if (scp->music) { - /* - mtx_unlock(&scp->seq_lock); - if (SYNTH_SETUPVOICE(md, voice, chn) - == EAGAIN) { - mtx_lock(&scp->seq_lock); - return (QUEUEFULL); - } - mtx_lock(&scp->seq_lock); - */ - } - SYNTH_STARTNOTE(md, voice, note, parm); - } - break; - case MIDI_NOTEOFF: - SYNTH_KILLNOTE(md, voice, note, parm); - break; - case MIDI_KEY_PRESSURE: - SYNTH_AFTERTOUCH(md, voice, parm); - break; - default: - ret = 1; - SEQ_DEBUG(2, printf("seq_chnvoice event type %d not handled\n", - event[1])); - break; - } - - mtx_lock(&scp->seq_lock); - return ret; -} - -static int -seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event) -{ - int ret; - u_short w14; - u_char cmd, chn, p1; - - ret = 0; - cmd = event[2]; - chn = event[3]; - p1 = event[4]; - w14 = *(u_short *)&event[6]; - - SEQ_DEBUG(5, printf("seq_chncommon: unit %d, dev %d, cmd %s, chn %d," - " p1 %d, w14 %d.\n", scp->unit, event[1], - midi_cmdname(cmd, cmdtab_seqccmn), chn, p1, w14)); - mtx_unlock(&scp->seq_lock); - switch (cmd) { - case MIDI_PGM_CHANGE: - SEQ_DEBUG(4, printf("seq_chncommon pgmchn chn %d pg %d\n", - chn, p1)); - SYNTH_SETINSTR(md, chn, p1); - break; - case MIDI_CTL_CHANGE: - SEQ_DEBUG(4, printf("seq_chncommon ctlch chn %d pg %d %d\n", - chn, p1, w14)); - SYNTH_CONTROLLER(md, chn, p1, w14); - break; - case MIDI_PITCH_BEND: - if (scp->music) { - /* - * TODO: MIDI_PITCH_BEND - */ -#if 0 - mtx_lock(&md->synth.vc_mtx); - md->synth.chn_info[chn].bender_value = w14; - if (md->midiunit >= 0) { - /* - * Handle all of the notes playing on this - * channel. - */ - key = ((int)chn << 8); - for (i = 0; i < md->synth.alloc.max_voice; i++) - if ((md->synth.alloc.map[i] & 0xff00) == key) { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&scp->seq_lock); - if (md->synth.bender(md, i, w14) == EAGAIN) { - mtx_lock(&scp->seq_lock); - return (QUEUEFULL); - } - mtx_lock(&scp->seq_lock); - } - } else { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&scp->seq_lock); - if (md->synth.bender(md, chn, w14) == EAGAIN) { - mtx_lock(&scp->seq_lock); - return (QUEUEFULL); - } - mtx_lock(&scp->seq_lock); - } -#endif - } else - SYNTH_BENDER(md, chn, w14); - break; - default: - ret = 1; - SEQ_DEBUG(2, - printf("seq_chncommon event type %d not handled.\n", - event[1])); - break; - } - mtx_lock(&scp->seq_lock); - return ret; -} - -static int -seq_timing(struct seq_softc *scp, u_char *event) -{ - int param; - int ret; - - ret = 0; - param = event[4] + (event[5] << 8) + - (event[6] << 16) + (event[7] << 24); - - SEQ_DEBUG(5, printf("seq_timing: unit %d, cmd %d, param %d.\n", - scp->unit, event[1], param)); - switch (event[1]) { - case TMR_WAIT_REL: - timer_wait(scp, param, 0); - break; - case TMR_WAIT_ABS: - timer_wait(scp, param, 1); - break; - case TMR_START: - timer_start(scp); - cv_broadcast(&scp->reset_cv); - break; - case TMR_STOP: - timer_stop(scp); - /* - * The following cv_broadcast isn't needed since we only - * wait for 0->1 transitions. It probably won't hurt - */ - cv_broadcast(&scp->reset_cv); - break; - case TMR_CONTINUE: - timer_continue(scp); - cv_broadcast(&scp->reset_cv); - break; - case TMR_TEMPO: - if (param < 8) - param = 8; - if (param > 360) - param = 360; - SEQ_DEBUG(4, printf("Timer set tempo %d\n", param)); - timer_setvals(scp, param, scp->timerbase); - break; - case TMR_TIMERBASE: - if (param < 1) - param = 1; - if (param > 1000) - param = 1000; - SEQ_DEBUG(4, printf("Timer set timerbase %d\n", param)); - timer_setvals(scp, scp->tempo, param); - break; - case TMR_ECHO: - /* - * TODO: Consider making 4-byte events for /dev/sequencer - * PRO: Maybe needed by legacy apps - * CON: soundcard.h has been warning for a while many years - * to expect 8 byte events. - */ -#if 0 - if (scp->music) - seq_copytoinput(scp, event, 8); - else { - param = (param << 8 | SEQ_ECHO); - seq_copytoinput(scp, (u_char *)¶m, 4); - } -#else - seq_copytoinput(scp, event, 8); -#endif - break; - default: - SEQ_DEBUG(2, printf("seq_timing event type %d not handled.\n", - event[1])); - ret = 1; - break; - } - return ret; -} - -static int -seq_local(struct seq_softc *scp, u_char *event) -{ - int ret; - - ret = 0; - mtx_assert(&scp->seq_lock, MA_OWNED); - - SEQ_DEBUG(5, printf("seq_local: unit %d, cmd %d\n", scp->unit, - event[1])); - switch (event[1]) { - default: - SEQ_DEBUG(1, printf("seq_local event type %d not handled\n", - event[1])); - ret = 1; - break; - } - return ret; -} - -static int -seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event) -{ - int i, l; - - mtx_assert(&scp->seq_lock, MA_OWNED); - SEQ_DEBUG(5, printf("seq_sysex: unit %d device %d\n", scp->unit, - event[1])); - l = 0; - for (i = 0; i < 6 && event[i + 2] != 0xff; i++) - l = i + 1; - if (l > 0) { - mtx_unlock(&scp->seq_lock); - if (SYNTH_SENDSYSEX(md, &event[2], l) == EAGAIN) { - mtx_lock(&scp->seq_lock); - return 1; - } - mtx_lock(&scp->seq_lock); - } - return 0; -} - -/* - * Reset no longer closes the raw devices nor seq_sync's - * Callers are IOCTL and seq_close - */ -static void -seq_reset(struct seq_softc *scp) -{ - int chn, i; - kobj_t m; - - mtx_assert(&scp->seq_lock, MA_OWNED); - - SEQ_DEBUG(5, printf("seq_reset: unit %d.\n", scp->unit)); - - /* - * Stop reading and writing. - */ - - /* scp->recording = 0; */ - scp->playing = 0; - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->out_cv); - cv_broadcast(&scp->reset_cv); - - /* - * For now, don't reset the timers. - */ - MIDIQ_CLEAR(scp->in_q); - MIDIQ_CLEAR(scp->out_q); - - for (i = 0; i < scp->midi_number; i++) { - m = scp->midis[i]; - mtx_unlock(&scp->seq_lock); - SYNTH_RESET(m); - for (chn = 0; chn < 16; chn++) { - SYNTH_CONTROLLER(m, chn, 123, 0); - SYNTH_CONTROLLER(m, chn, 121, 0); - SYNTH_BENDER(m, chn, 1 << 13); - } - mtx_lock(&scp->seq_lock); - } -} - -/* - * seq_sync - * *really* flush the output queue - * flush the event queue, then flush the synthsisers. - * Callers are IOCTL and close - */ - -#define SEQ_SYNC_TIMEOUT 8 -static int -seq_sync(struct seq_softc *scp) -{ - int i, rl, sync[16], done; - - mtx_assert(&scp->seq_lock, MA_OWNED); - - SEQ_DEBUG(4, printf("seq_sync: unit %d.\n", scp->unit)); - - /* - * Wait until output queue is empty. Check every so often to see if - * the queue is moving along. If it isn't just abort. - */ - while (!MIDIQ_EMPTY(scp->out_q)) { - if (!scp->playing) { - scp->playing = 1; - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->out_cv); - } - rl = MIDIQ_LEN(scp->out_q); - - i = cv_timedwait_sig(&scp->out_cv, - &scp->seq_lock, SEQ_SYNC_TIMEOUT * hz); - - if (i == EINTR || i == ERESTART) { - if (i == EINTR) { - /* - * XXX: I don't know why we stop playing - */ - scp->playing = 0; - cv_broadcast(&scp->out_cv); - } - return i; - } - if (i == EWOULDBLOCK && rl == MIDIQ_LEN(scp->out_q) && - scp->waiting == 0) { - /* - * A queue seems to be stuck up. Give up and clear - * queues. - */ - MIDIQ_CLEAR(scp->out_q); - scp->playing = 0; - cv_broadcast(&scp->state_cv); - cv_broadcast(&scp->out_cv); - cv_broadcast(&scp->reset_cv); - - /* - * TODO: Consider if the raw devices need to be flushed - */ - - SEQ_DEBUG(1, printf("seq_sync queue stuck, aborting\n")); - - return i; - } - } - - scp->playing = 0; - /* - * Since syncing a midi device might block, unlock scp->seq_lock. - */ - - mtx_unlock(&scp->seq_lock); - for (i = 0; i < scp->midi_number; i++) - sync[i] = 1; - - do { - done = 1; - for (i = 0; i < scp->midi_number; i++) - if (sync[i]) { - if (SYNTH_INSYNC(scp->midis[i]) == 0) - sync[i] = 0; - else - done = 0; - } - if (!done) - DELAY(5000); - - } while (!done); - - mtx_lock(&scp->seq_lock); - return 0; -} - -char * -midi_cmdname(int cmd, midi_cmdtab *tab) -{ - while (tab->name != NULL) { - if (cmd == tab->cmd) - return (tab->name); - tab++; - } - - return ("unknown"); -} diff --git a/sys/dev/sound/midi/synth_if.m b/sys/dev/sound/midi/synth_if.m deleted file mode 100644 index a763b3422bc6..000000000000 --- a/sys/dev/sound/midi/synth_if.m +++ /dev/null @@ -1,312 +0,0 @@ -#- -# Copyright (c) 2003 Mathew Kanner -# All rights reserved. -# -# 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. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. -# -# - -INTERFACE synth; - -#include <sys/systm.h> - -CODE { - -synth_killnote_t nokillnote; -synth_startnote_t nostartnote; -synth_setinstr_t nosetinstr; -synth_hwcontrol_t nohwcontrol; -synth_aftertouch_t noaftertouch; -synth_panning_t nopanning; -synth_controller_t nocontroller; -synth_volumemethod_t novolumemethod; -synth_bender_t nobender; -synth_setupvoice_t nosetupvoice; -synth_sendsysex_t nosendsysex; -synth_allocvoice_t noallocvoice; -synth_writeraw_t nowriteraw; -synth_reset_t noreset; -synth_shortname_t noshortname; -synth_open_t noopen; -synth_close_t noclose; -synth_query_t noquery; -synth_insync_t noinsync; -synth_alloc_t noalloc; - - int - nokillnote(void *_kobj, uint8_t _chn, uint8_t _note, uint8_t _vel) - { - printf("nokillnote\n"); - return 0; - } - - int - noopen(void *_kobj, void *_arg, int mode) - { - printf("noopen\n"); - return 0; - } - - int - noquery(void *_kboj) - { - printf("noquery\n"); - return 0; - } - - int - nostartnote(void *_kb, uint8_t _voice, uint8_t _note, uint8_t _parm) - { - printf("nostartnote\n"); - return 0; - } - - int - nosetinstr(void *_kb, uint8_t _chn, uint16_t _patchno) - { - printf("nosetinstr\n"); - return 0; - } - - int - nohwcontrol(void *_kb, uint8_t *_event) - { - printf("nohwcontrol\n"); - return 0; - } - - int - noaftertouch ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2) - { - printf("noaftertouch\n"); - return 0; - } - - int - nopanning ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2) - { - printf("nopanning\n"); - return 0; - } - - int - nocontroller ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2, uint16_t _x3) - { - printf("nocontroller\n"); - return 0; - } - - int - novolumemethod ( - void /* X */ * _kobj, - uint8_t _x1) - { - printf("novolumemethod\n"); - return 0; - } - - int - nobender ( void /* X */ * _kobj, uint8_t _voice, uint16_t _bend) - { - printf("nobender\n"); - return 0; - } - - int - nosetupvoice ( void /* X */ * _kobj, uint8_t _voice, uint8_t _chn) - { - - printf("nosetupvoice\n"); - return 0; - } - - int - nosendsysex ( void /* X */ * _kobj, void * _buf, size_t _len) - { - printf("nosendsysex\n"); - return 0; - } - - int - noallocvoice ( void /* X */ * _kobj, uint8_t _chn, uint8_t _note, void *_x) - { - printf("noallocvoice\n"); - return 0; - } - - int - nowriteraw ( void /* X */ * _kobjt, uint8_t * _buf, size_t _len) - { - printf("nowriteraw\n"); - return 1; - } - - int - noreset ( void /* X */ * _kobjt) - { - - printf("noreset\n"); - return 0; - } - - char * - noshortname (void /* X */ * _kobjt) - { - printf("noshortname\n"); - return "noshortname"; - } - - int - noclose ( void /* X */ * _kobjt) - { - - printf("noclose\n"); - return 0; - } - - int - noinsync (void /* X */ * _kobjt) - { - - printf("noinsync\n"); - return 0; - } - - int - noalloc ( void /* x */ * _kbojt, uint8_t _chn, uint8_t _note) - { - printf("noalloc\n"); - return 0; - } -} - -METHOD int killnote { - void /* X */ *_kobj; - uint8_t _chan; - uint8_t _note; - uint8_t _vel; -} DEFAULT nokillnote; - -METHOD int startnote { - void /* X */ *_kobj; - uint8_t _voice; - uint8_t _note; - uint8_t _parm; -} DEFAULT nostartnote; - -METHOD int setinstr { - void /* X */ *_kobj; - uint8_t _chn; - uint16_t _patchno; -} DEFAULT nosetinstr; - -METHOD int hwcontrol { - void /* X */ *_kobj; - uint8_t *_event; -} DEFAULT nohwcontrol; - -METHOD int aftertouch { - void /* X */ *_kobj; - uint8_t _x1; - uint8_t _x2; -} DEFAULT noaftertouch; - -METHOD int panning { - void /* X */ *_kobj; - uint8_t _x1; - uint8_t _x2; -} DEFAULT nopanning; - -METHOD int controller { - void /* X */ *_kobj; - uint8_t _x1; - uint8_t _x2; - uint16_t _x3; -} DEFAULT nocontroller; - -METHOD int volumemethod { - void /* X */ *_kobj; - uint8_t _x1; -} DEFAULT novolumemethod; - -METHOD int bender { - void /* X */ *_kobj; - uint8_t _voice; - uint16_t _bend; -} DEFAULT nobender; - -METHOD int setupvoice { - void /* X */ *_kobj; - uint8_t _voice; - uint8_t _chn; -} DEFAULT nosetupvoice; - -METHOD int sendsysex { - void /* X */ *_kobj; - void *_buf; - size_t _len; -} DEFAULT nosendsysex; - -METHOD int allocvoice { - void /* X */ *_kobj; - uint8_t _chn; - uint8_t _note; - void *_x; -} DEFAULT noallocvoice; - -METHOD int writeraw { - void /* X */ *_kobjt; - uint8_t *_buf; - size_t _len; -} DEFAULT nowriteraw; - -METHOD int reset { - void /* X */ *_kobjt; -} DEFAULT noreset; - -METHOD char * shortname { - void /* X */ *_kobjt; -} DEFAULT noshortname; - -METHOD int open { - void /* X */ *_kobjt; - void *_sythn; - int _mode; -} DEFAULT noopen; - -METHOD int close { - void /* X */ *_kobjt; -} DEFAULT noclose; - -METHOD int query { - void /* X */ *_kobjt; -} DEFAULT noquery; - -METHOD int insync { - void /* X */ *_kobjt; -} DEFAULT noinsync; - -METHOD int alloc { - void /* x */ *_kbojt; - uint8_t _chn; - uint8_t _note; -} DEFAULT noalloc; diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index 092af3298f0e..f281dff36248 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -750,8 +750,8 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) mixer_setrecsrc(m, 0); /* Set default input. */ - pdev = make_dev(&mixer_cdevsw, SND_DEV_CTL, UID_ROOT, GID_WHEEL, 0666, - "mixer%d", unit); + pdev = make_dev(&mixer_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "mixer%d", + unit); pdev->si_drv1 = m; snddev->mixer_dev = pdev; diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c index 509a35c5a038..51d0fb3bb686 100644 --- a/sys/dev/sound/pcm/sndstat.c +++ b/sys/dev/sound/pcm/sndstat.c @@ -52,7 +52,6 @@ #define SS_TYPE_PCM 1 #define SS_TYPE_MIDI 2 -#define SS_TYPE_SEQUENCER 3 static d_open_t sndstat_open; static void sndstat_close(void *); @@ -1165,8 +1164,6 @@ sndstat_register(device_t dev, char *str) type = SS_TYPE_PCM; else if (!strcmp(devtype, "midi")) type = SS_TYPE_MIDI; - else if (!strcmp(devtype, "sequencer")) - type = SS_TYPE_SEQUENCER; else return (EINVAL); @@ -1441,8 +1438,8 @@ static void sndstat_sysinit(void *p) { sx_init(&sndstat_lock, "sndstat lock"); - sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, - UID_ROOT, GID_WHEEL, 0644, "sndstat"); + sndstat_dev = make_dev(&sndstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, + "sndstat"); } SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL); diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 315452e294d1..6bd435d0ea25 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -148,14 +148,6 @@ struct snd_mixer; #define RANGE(var, low, high) (var) = \ (((var)<(low))? (low) : ((var)>(high))? (high) : (var)) -enum { - SND_DEV_CTL = 0, /* Control port /dev/mixer */ - SND_DEV_SEQ, /* Sequencer /dev/sequencer */ - SND_DEV_MIDIN, /* Raw midi access */ - SND_DEV_DSP, /* Digitized voice /dev/dsp */ - SND_DEV_STATUS, /* /dev/sndstat */ -}; - #define DSP_DEFAULT_SPEED 8000 extern int snd_unit; diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h index cac743884ee6..ac58d44102a0 100644 --- a/sys/dev/ufshci/ufshci_private.h +++ b/sys/dev/ufshci/ufshci_private.h @@ -149,6 +149,8 @@ struct ufshci_hw_queue { bus_dmamap_t queuemem_map; bus_addr_t req_queue_addr; + bus_addr_t *ucd_bus_addr; + uint32_t num_entries; uint32_t num_trackers; @@ -198,8 +200,6 @@ struct ufshci_req_queue { bus_dma_tag_t dma_tag_payload; bus_dmamap_t ucdmem_map; - - bus_addr_t ucd_addr; }; struct ufshci_device { diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c index 4670281d367a..b1f303afaef5 100644 --- a/sys/dev/ufshci/ufshci_req_sdb.c +++ b/sys/dev/ufshci/ufshci_req_sdb.c @@ -48,6 +48,29 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue) } } +static void +ufshci_ucd_map(void *arg, bus_dma_segment_t *seg, int nseg, int error) +{ + struct ufshci_hw_queue *hwq = arg; + int i; + + if (error != 0) { + printf("ufshci: Failed to map UCD, error = %d\n", error); + return; + } + + if (hwq->num_trackers != nseg) { + printf( + "ufshci: Failed to map UCD, num_trackers = %d, nseg = %d\n", + hwq->num_trackers, nseg); + return; + } + + for (i = 0; i < nseg; i++) { + hwq->ucd_bus_addr[i] = seg[i].ds_addr; + } +} + static int ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, uint32_t num_entries, struct ufshci_controller *ctrlr) @@ -55,7 +78,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q]; struct ufshci_tracker *tr; size_t ucd_allocsz, payload_allocsz; - uint64_t ucdmem_phys; uint8_t *ucdmem; int i, error; @@ -71,10 +93,11 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, * Allocate physical memory for UTP Command Descriptor (UCD) * Note: UFSHCI UCD format is restricted to 128-byte alignment. */ - error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128, - ctrlr->page_size, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - ucd_allocsz, howmany(ucd_allocsz, ctrlr->page_size), - ctrlr->page_size, 0, NULL, NULL, &req_queue->dma_tag_ucd); + error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, ucd_allocsz, + howmany(ucd_allocsz, sizeof(struct ufshci_utp_cmd_desc)), + sizeof(struct ufshci_utp_cmd_desc), 0, NULL, NULL, + &req_queue->dma_tag_ucd); if (error != 0) { ufshci_printf(ctrlr, "request cmd desc tag create failed %d\n", error); @@ -88,7 +111,7 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, } if (bus_dmamap_load(req_queue->dma_tag_ucd, req_queue->ucdmem_map, - ucdmem, ucd_allocsz, ufshci_single_map, &ucdmem_phys, 0) != 0) { + ucdmem, ucd_allocsz, ufshci_ucd_map, hwq, 0) != 0) { ufshci_printf(ctrlr, "failed to load cmd desc memory\n"); bus_dmamem_free(req_queue->dma_tag_ucd, req_queue->ucd, req_queue->ucdmem_map); @@ -96,7 +119,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, } req_queue->ucd = (struct ufshci_utp_cmd_desc *)ucdmem; - req_queue->ucd_addr = ucdmem_phys; /* * Allocate physical memory for PRDT @@ -128,10 +150,9 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, tr->slot_state = UFSHCI_SLOT_STATE_FREE; tr->ucd = (struct ufshci_utp_cmd_desc *)ucdmem; - tr->ucd_bus_addr = ucdmem_phys; + tr->ucd_bus_addr = hwq->ucd_bus_addr[i]; ucdmem += sizeof(struct ufshci_utp_cmd_desc); - ucdmem_phys += sizeof(struct ufshci_utp_cmd_desc); hwq->act_tr[i] = tr; } @@ -175,6 +196,11 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, req_queue->hwq = malloc(sizeof(struct ufshci_hw_queue), M_UFSHCI, M_ZERO | M_NOWAIT); hwq = &req_queue->hwq[UFSHCI_SDB_Q]; + hwq->num_entries = req_queue->num_entries; + hwq->num_trackers = req_queue->num_trackers; + req_queue->hwq->ucd_bus_addr = malloc(sizeof(bus_addr_t) * + req_queue->num_trackers, + M_UFSHCI, M_ZERO | M_NOWAIT); mtx_init(&hwq->qlock, "ufshci req_queue lock", NULL, MTX_DEF); @@ -277,6 +303,7 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr, if (mtx_initialized(&hwq->qlock)) mtx_destroy(&hwq->qlock); + free(req_queue->hwq->ucd_bus_addr, M_UFSHCI); free(req_queue->hwq, M_UFSHCI); } diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c index b50e33ea36ce..d5cfd228a429 100644 --- a/sys/dev/usb/controller/xhci_pci.c +++ b/sys/dev/usb/controller/xhci_pci.c @@ -99,6 +99,11 @@ xhci_pci_match(device_t self) return ("AMD Starship USB 3.0 controller"); case 0x149c1022: return ("AMD Matisse USB 3.0 controller"); + case 0x15b61022: + case 0x15b71022: + return ("AMD Raphael/Granite Ridge USB 3.1 controller"); + case 0x15b81022: + return ("AMD Raphael/Granite Ridge USB 2.0 controller"); case 0x15e01022: case 0x15e11022: return ("AMD Raven USB 3.1 controller"); @@ -109,6 +114,8 @@ xhci_pci_match(device_t self) return ("AMD 300 Series USB 3.1 controller"); case 0x43d51022: return ("AMD 400 Series USB 3.1 controller"); + case 0x43f71022: + return ("AMD 600 Series USB 3.2 controller"); case 0x78121022: case 0x78141022: case 0x79141022: diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index 676ea5de12b8..58a22b8bdc50 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/fdesc_vnops.c @@ -547,6 +547,8 @@ fdesc_readdir(struct vop_readdir_args *ap) fmp = VFSTOFDESC(ap->a_vp->v_mount); if (ap->a_ncookies != NULL) *ap->a_ncookies = 0; + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 0; off = (int)uio->uio_offset; if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 || @@ -559,7 +561,12 @@ fdesc_readdir(struct vop_readdir_args *ap) fcnt = i - 2; /* The first two nodes are `.' and `..' */ FILEDESC_SLOCK(fdp); - while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) { + while (uio->uio_resid >= UIO_MX) { + if (i >= fdp->fd_nfiles + 2) { + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 1; + break; + } bzero((caddr_t)dp, UIO_MX); switch (i) { case 0: /* `.' */ diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index 120b97ba72d5..33e0d94954d7 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -1521,6 +1521,9 @@ msdosfs_readdir(struct vop_readdir_args *ap) ap->a_vp, uio, ap->a_cred, ap->a_eofflag); #endif + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 0; + /* * msdosfs_readdir() won't operate properly on regular files since * it does i/o only with the filesystem vnode, and hence can @@ -1614,8 +1617,11 @@ msdosfs_readdir(struct vop_readdir_args *ap) on = (offset - bias) & pmp->pm_crbomask; n = min(pmp->pm_bpcluster - on, uio->uio_resid); diff = dep->de_FileSize - (offset - bias); - if (diff <= 0) - break; + if (diff <= 0) { + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 1; + goto out; + } n = min(n, diff); error = pcbmap(dep, lbn, &bn, &cn, &blsize); if (error) @@ -1646,6 +1652,8 @@ msdosfs_readdir(struct vop_readdir_args *ap) */ if (dentp->deName[0] == SLOT_EMPTY) { brelse(bp); + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 1; goto out; } /* @@ -1743,15 +1751,6 @@ out: uio->uio_offset = off; - /* - * Set the eofflag (NFS uses it) - */ - if (ap->a_eofflag) { - if (dep->de_FileSize - (offset - bias) <= 0) - *ap->a_eofflag = 1; - else - *ap->a_eofflag = 0; - } return (error); } @@ -1942,6 +1941,9 @@ msdosfs_pathconf(struct vop_pathconf_args *ap) case _PC_NO_TRUNC: *ap->a_retval = 0; return (0); + case _PC_HAS_HIDDENSYSTEM: + *ap->a_retval = 1; + return (0); default: return (vop_stdpathconf(ap)); } diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index f46b0d282861..4c498e96a3c0 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -630,6 +630,10 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap, NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP); if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); + if ((flags & NFSSATTR_FULL) && vap->va_flags != VNOVAL) { + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); + } if (vap->va_atime.tv_sec != VNOVAL) NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); if (vap->va_mtime.tv_sec != VNOVAL) @@ -1314,6 +1318,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, u_int32_t freenum = 0, tuint; u_int64_t uquad = 0, thyp, thyp2; uint16_t tui16; + long has_pathconf; #ifdef QUOTA struct dqblk dqb; uid_t savuid; @@ -1421,6 +1426,16 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL); NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT); } + /* Some filesystems do not support uf_hidden */ + if (vp == NULL || VOP_PATHCONF(vp, + _PC_HAS_HIDDENSYSTEM, &has_pathconf) != 0) + has_pathconf = 0; + if (has_pathconf == 0) { + NFSCLRBIT_ATTRBIT(&checkattrbits, + NFSATTRBIT_HIDDEN); + NFSCLRBIT_ATTRBIT(&checkattrbits, + NFSATTRBIT_SYSTEM); + } if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) || retnotsup) *retcmpp = NFSERR_NOTSAME; @@ -1521,15 +1536,13 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (compare) { if (!(*retcmpp)) { - long has_named_attr; - if (vp == NULL || VOP_PATHCONF(vp, - _PC_HAS_NAMEDATTR, &has_named_attr) + _PC_HAS_NAMEDATTR, &has_pathconf) != 0) - has_named_attr = 0; - if ((has_named_attr != 0 && + has_pathconf = 0; + if ((has_pathconf != 0 && *tl != newnfs_true) || - (has_named_attr == 0 && + (has_pathconf == 0 && *tl != newnfs_false)) *retcmpp = NFSERR_NOTSAME; } @@ -1792,9 +1805,17 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, free(cp2, M_NFSSTRING); break; case NFSATTRBIT_HIDDEN: - NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); - if (compare && !(*retcmpp)) - *retcmpp = NFSERR_ATTRNOTSUPP; + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp) && ((*tl == newnfs_true && + (nap->na_flags & UF_HIDDEN) == 0) || + (*tl == newnfs_false && + (nap->na_flags & UF_HIDDEN) != 0))) + *retcmpp = NFSERR_NOTSAME; + } else if (nap != NULL) { + if (*tl == newnfs_true) + nap->na_flags |= UF_HIDDEN; + } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_HOMOGENEOUS: @@ -2166,9 +2187,17 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, attrsum += NFSX_HYPER; break; case NFSATTRBIT_SYSTEM: - NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); - if (compare && !(*retcmpp)) - *retcmpp = NFSERR_ATTRNOTSUPP; + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp) && ((*tl == newnfs_true && + (nap->na_flags & UF_SYSTEM) == 0) || + (*tl == newnfs_false && + (nap->na_flags & UF_SYSTEM) != 0))) + *retcmpp = NFSERR_NOTSAME; + } else if (nap != NULL) { + if (*tl == newnfs_true) + nap->na_flags |= UF_SYSTEM; + } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_TIMEACCESS: @@ -2634,7 +2663,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, size_t atsiz; bool xattrsupp; short irflag; - long has_named_attr; + long has_pathconf; #ifdef QUOTA struct dqblk dqb; uid_t savuid; @@ -2751,6 +2780,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); } + if (cred == NULL || p == NULL || vp == NULL || + VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM, + &has_pathconf) != 0) + has_pathconf = 0; + if (has_pathconf == 0) { + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); + } retnum += nfsrv_putattrbit(nd, &attrbits); break; case NFSATTRBIT_TYPE: @@ -2791,10 +2828,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, break; case NFSATTRBIT_NAMEDATTR: NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); - if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, &has_named_attr) - != 0) - has_named_attr = 0; - if (has_named_attr != 0) + if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, + &has_pathconf) != 0) + has_pathconf = 0; + if (has_pathconf != 0) *tl = newnfs_true; else *tl = newnfs_false; @@ -2899,6 +2936,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, *tl = 0; retnum += 2 * NFSX_UNSIGNED; break; + case NFSATTRBIT_HIDDEN: + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + if ((vap->va_flags & UF_HIDDEN) != 0) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; case NFSATTRBIT_HOMOGENEOUS: NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) @@ -3088,6 +3133,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, txdr_hyper(vap->va_bytes, tl); retnum += NFSX_HYPER; break; + case NFSATTRBIT_SYSTEM: + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + if ((vap->va_flags & UF_SYSTEM) != 0) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; case NFSATTRBIT_TIMEACCESS: NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); txdr_nfsv4time(&vap->va_atime, tl); diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index eff53e1a384e..cb5a80e8df73 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -1142,6 +1142,7 @@ struct nfsv3_sattr { NFSATTRBM_FILESFREE | \ NFSATTRBM_FILESTOTAL | \ NFSATTRBM_FSLOCATIONS | \ + NFSATTRBM_HIDDEN | \ NFSATTRBM_HOMOGENEOUS | \ NFSATTRBM_MAXFILESIZE | \ NFSATTRBM_MAXLINK | \ @@ -1163,6 +1164,7 @@ struct nfsv3_sattr { NFSATTRBM_SPACEFREE | \ NFSATTRBM_SPACETOTAL | \ NFSATTRBM_SPACEUSED | \ + NFSATTRBM_SYSTEM | \ NFSATTRBM_TIMEACCESS | \ NFSATTRBM_TIMECREATE | \ NFSATTRBM_TIMEDELTA | \ @@ -1210,11 +1212,13 @@ struct nfsv3_sattr { */ #define NFSATTRBIT_SETABLE0 \ (NFSATTRBM_SIZE | \ + NFSATTRBM_HIDDEN | \ NFSATTRBM_ACL) #define NFSATTRBIT_SETABLE1 \ (NFSATTRBM_MODE | \ NFSATTRBM_OWNER | \ NFSATTRBM_OWNERGROUP | \ + NFSATTRBM_SYSTEM | \ NFSATTRBM_TIMECREATE | \ NFSATTRBM_TIMEACCESSSET | \ NFSATTRBM_TIMEMODIFYSET) @@ -1254,6 +1258,7 @@ struct nfsv3_sattr { NFSATTRBM_SIZE | \ NFSATTRBM_FSID | \ NFSATTRBM_FILEID | \ + NFSATTRBM_HIDDEN | \ NFSATTRBM_MAXREAD) /* @@ -1266,6 +1271,7 @@ struct nfsv3_sattr { NFSATTRBM_OWNERGROUP | \ NFSATTRBM_RAWDEV | \ NFSATTRBM_SPACEUSED | \ + NFSATTRBM_SYSTEM | \ NFSATTRBM_TIMEACCESS | \ NFSATTRBM_TIMECREATE | \ NFSATTRBM_TIMEMETADATA | \ @@ -1288,6 +1294,7 @@ struct nfsv3_sattr { NFSATTRBM_SIZE | \ NFSATTRBM_FSID | \ NFSATTRBM_FILEID | \ + NFSATTRBM_HIDDEN | \ NFSATTRBM_MAXREAD) /* @@ -1298,6 +1305,7 @@ struct nfsv3_sattr { NFSATTRBM_NUMLINKS | \ NFSATTRBM_RAWDEV | \ NFSATTRBM_SPACEUSED | \ + NFSATTRBM_SYSTEM | \ NFSATTRBM_TIMEACCESS | \ NFSATTRBM_TIMECREATE | \ NFSATTRBM_TIMEMETADATA | \ diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index c07da6f9275f..e0e66baca44d 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -4158,6 +4158,13 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_TIMECREATE)) NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); + if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, + NFSATTRBIT_HIDDEN) || + !NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, + NFSATTRBIT_SYSTEM)) { + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); + } } /* diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 0049d7edca33..fa451887e73e 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1074,21 +1074,29 @@ nfs_setattr(struct vop_setattr_args *ap) int error = 0; u_quad_t tsize; struct timespec ts; + struct nfsmount *nmp; #ifndef nolint tsize = (u_quad_t)0; #endif /* - * Setting of flags and marking of atimes are not supported. + * Only setting of UF_HIDDEN and UF_SYSTEM are supported and + * only for NFSv4 servers that support them. */ - if (vap->va_flags != VNOVAL) + nmp = VFSTONFS(vp->v_mount); + if (vap->va_flags != VNOVAL && (!NFSHASNFSV4(nmp) || + (vap->va_flags & ~(UF_HIDDEN | UF_SYSTEM)) != 0 || + ((vap->va_flags & UF_HIDDEN) != 0 && + !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN)) || + ((vap->va_flags & UF_SYSTEM) != 0 && + !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_SYSTEM)))) return (EOPNOTSUPP); /* * Disallow write attempts if the filesystem is mounted read-only. */ - if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + if ((vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL || @@ -4754,6 +4762,15 @@ nfs_pathconf(struct vop_pathconf_args *ap) else *ap->a_retval = 0; break; + case _PC_HAS_HIDDENSYSTEM: + if (NFS_ISV4(vp) && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, + NFSATTRBIT_HIDDEN) && + NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, + NFSATTRBIT_SYSTEM)) + *ap->a_retval = 1; + else + *ap->a_retval = 0; + break; default: error = vop_stdpathconf(ap); diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 3bf54d82b959..43ee0383669f 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -449,6 +449,7 @@ nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, } nvap->na_bsdflags = 0; + nvap->na_flags = 0; error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred); if (lockedit != 0) NFSVOPUNLOCK(vp); @@ -1651,10 +1652,11 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp, } if (fvp == tvp) { /* - * If source and destination are the same, there is nothing to - * do. Set error to -1 to indicate this. + * If source and destination are the same, there is + * nothing to do. Set error to EJUSTRETURN to indicate + * this. */ - error = -1; + error = EJUSTRETURN; goto out; } if (nd->nd_flag & ND_NFSV4) { @@ -1696,10 +1698,26 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp, " dsdvp=%p\n", dsdvp[0]); } out: - if (!error) { + mp = NULL; + if (error == 0) { + error = VOP_GETWRITEMOUNT(tondp->ni_dvp, &mp); + if (error == 0) { + if (mp == NULL) { + error = ENOENT; + } else { + error = lockmgr(&mp->mnt_renamelock, + LK_EXCLUSIVE | LK_NOWAIT, NULL); + if (error != 0) + error = ERELOOKUP; + } + } + } + if (error == 0) { error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp, &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp, &tondp->ni_cnd); + lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); + vfs_rel(mp); } else { if (tdvp == tvp) vrele(tdvp); @@ -1709,8 +1727,13 @@ out: vput(tvp); vrele(fromndp->ni_dvp); vrele(fvp); - if (error == -1) + if (error == EJUSTRETURN) { error = 0; + } else if (error == ERELOOKUP && mp != NULL) { + lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0); + lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); + vfs_rel(mp); + } } /* @@ -3127,6 +3150,9 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, bitpos = NFSATTRBIT_MAX; } else { bitpos = 0; + if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN) || + NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM)) + nvap->na_flags = 0; } moderet = 0; for (; bitpos < NFSATTRBIT_MAX; bitpos++) { @@ -3163,9 +3189,11 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_HIDDEN: - NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); - if (!nd->nd_repstat) - nd->nd_repstat = NFSERR_ATTRNOTSUPP; + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (nd->nd_repstat == 0) { + if (*tl == newnfs_true) + nvap->na_flags |= UF_HIDDEN; + } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_MIMETYPE: @@ -3240,9 +3268,11 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); break; case NFSATTRBIT_SYSTEM: - NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); - if (!nd->nd_repstat) - nd->nd_repstat = NFSERR_ATTRNOTSUPP; + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (nd->nd_repstat == 0) { + if (*tl == newnfs_true) + nvap->na_flags |= UF_SYSTEM; + } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_TIMEACCESSSET: diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index 4e15d55eb312..f7564ade401b 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -403,8 +403,10 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, if (error) goto nfsmout; - /* For NFSv4, only va_uid is used from nva2. */ + /* For NFSv4, only va_uid and va_flags is used from nva2. */ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); if (!nd->nd_repstat) nd->nd_repstat = preat_ret; @@ -463,6 +465,9 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, &nva, &attrbits, exp, p); if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { + u_long oldflags; + + oldflags = nva2.na_flags; /* * For V4, try setting the attributes in sets, so that the * reply bitmap will be correct for an error case. @@ -532,6 +537,32 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); } } + if (!nd->nd_repstat && + (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) || + NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) { + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) { + if ((nva.na_flags & UF_HIDDEN) != 0) + oldflags |= UF_HIDDEN; + else + oldflags &= ~UF_HIDDEN; + } + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) { + if ((nva.na_flags & UF_SYSTEM) != 0) + oldflags |= UF_SYSTEM; + else + oldflags &= ~UF_SYSTEM; + } + NFSVNO_ATTRINIT(&nva2); + NFSVNO_SETATTRVAL(&nva2, flags, oldflags); + nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, + exp); + if (!nd->nd_repstat) { + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); + if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) + NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); + } + } #ifdef NFS4_ACL_EXTATTR_NAME if (!nd->nd_repstat && aclp->acl_cnt > 0 && diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c index 56bf766ef801..227e2b93883e 100644 --- a/sys/fs/p9fs/p9fs_vnops.c +++ b/sys/fs/p9fs/p9fs_vnops.c @@ -1784,6 +1784,9 @@ p9fs_readdir(struct vop_readdir_args *ap) return (EBADF); } + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 0; + io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK); /* We haven't reached the end yet. read more. */ @@ -1801,8 +1804,11 @@ p9fs_readdir(struct vop_readdir_args *ap) count = p9_client_readdir(vofid, (char *)io_buffer, diroffset, count); - if (count == 0) + if (count == 0) { + if (ap->a_eofflag != NULL) + *ap->a_eofflag = 1; break; + } if (count < 0) { error = EIO; diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c index c30995508c00..5d412cabadb8 100644 --- a/sys/fs/smbfs/smbfs_vnops.c +++ b/sys/fs/smbfs/smbfs_vnops.c @@ -810,6 +810,9 @@ smbfs_pathconf(struct vop_pathconf_args *ap) case _PC_NO_TRUNC: *retval = 1; break; + case _PC_HAS_HIDDENSYSTEM: + *retval = 1; + break; default: error = vop_stdpathconf(ap); } diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index c99d0732be50..9d2a587b177a 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -1691,6 +1691,10 @@ tmpfs_pathconf(struct vop_pathconf_args *v) *retval = PAGE_SIZE; break; + case _PC_HAS_HIDDENSYSTEM: + *retval = 1; + break; + default: error = vop_stdpathconf(v); } diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h index 839bbec08254..19e114763cac 100644 --- a/sys/fs/udf/ecma167-udf.h +++ b/sys/fs/udf/ecma167-udf.h @@ -243,7 +243,7 @@ struct part_map_spare { uint8_t n_st; /* Number of Sparing Tables */ uint8_t reserved1; uint32_t st_size; - uint32_t st_loc[1]; + uint32_t st_loc[]; } __packed; union udf_pmap { @@ -266,7 +266,7 @@ struct udf_sparing_table { uint16_t rt_l; /* Relocation Table len */ uint8_t reserved[2]; uint32_t seq_num; - struct spare_map_entry entries[1]; + struct spare_map_entry entries[]; } __packed; /* Partition Descriptor [3/10.5] */ diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index c7438147c0a0..c5ef1f686093 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -81,6 +81,7 @@ #include <sys/fcntl.h> #include <sys/iconv.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/malloc.h> #include <sys/mount.h> #include <sys/namei.h> @@ -729,7 +730,7 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) struct ifid *ifhp; struct vnode *nvp; struct udf_node *np; - off_t fsize; + uint64_t fsize; int error; ifhp = (struct ifid *)fhp; @@ -741,6 +742,10 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) np = VTON(nvp); fsize = le64toh(np->fentry->inf_len); + if (fsize > OFF_MAX) { + *vpp = NULLVP; + return (EIO); + } *vpp = nvp; vnode_create_vobject(*vpp, fsize, curthread); diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index 88bf4917a851..37889241e8c3 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -39,6 +39,7 @@ #include <sys/conf.h> #include <sys/buf.h> #include <sys/iconv.h> +#include <sys/limits.h> #include <sys/mount.h> #include <sys/vnode.h> #include <sys/dirent.h> @@ -182,11 +183,14 @@ udf_access(struct vop_access_args *a) } static int -udf_open(struct vop_open_args *ap) { +udf_open(struct vop_open_args *ap) +{ struct udf_node *np = VTON(ap->a_vp); - off_t fsize; + uint64_t fsize; fsize = le64toh(np->fentry->inf_len); + if (fsize > OFF_MAX) + return (EIO); vnode_create_vobject(ap->a_vp, fsize, ap->a_td); return 0; } @@ -314,12 +318,13 @@ udf_getattr(struct vop_getattr_args *a) * that directories consume at least one logical block, * make it appear so. */ - if (fentry->logblks_rec != 0) { - vap->va_size = - le64toh(fentry->logblks_rec) * node->udfmp->bsize; - } else { + vap->va_size = le64toh(fentry->logblks_rec); + if (vap->va_size == 0) vap->va_size = node->udfmp->bsize; - } + else if (vap->va_size > UINT64_MAX / node->udfmp->bsize) + vap->va_size = UINT64_MAX; + else + vap->va_size *= node->udfmp->bsize; } else { vap->va_size = le64toh(fentry->inf_len); } @@ -446,6 +451,7 @@ udf_read(struct vop_read_args *ap) struct buf *bp; uint8_t *data; daddr_t lbn, rablock; + uint64_t len; off_t diff, fsize; ssize_t n; int error = 0; @@ -471,7 +477,12 @@ udf_read(struct vop_read_args *ap) return (error); } - fsize = le64toh(node->fentry->inf_len); + len = le64toh(node->fentry->inf_len); + if (len > OFF_MAX) { + /* too big, just cap to the requested length */ + len = uio->uio_resid; + } + fsize = len; udfmp = node->udfmp; do { lbn = lblkno(udfmp, uio->uio_offset); @@ -783,6 +794,7 @@ udf_readdir(struct vop_readdir_args *a) struct udf_uiodir uiodir; struct udf_dirstream *ds; uint64_t *cookies = NULL; + uint64_t len; int ncookies; int error = 0; @@ -811,8 +823,12 @@ udf_readdir(struct vop_readdir_args *a) * Iterate through the file id descriptors. Give the parent dir * entry special attention. */ - ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len), - node->udfmp); + len = le64toh(node->fentry->inf_len); + if (len > INT_MAX) { + /* too big, just cap to INT_MAX */ + len = INT_MAX; + } + ds = udf_opendir(node, uio->uio_offset, len, node->udfmp); while ((fid = udf_getfid(ds)) != NULL) { /* XXX Should we return an error on a bad fid? */ @@ -904,7 +920,8 @@ udf_readlink(struct vop_readlink_args *ap) struct udf_node *node; void *buf; char *cp; - int error, len, root; + uint64_t len; + int error, root; /* * A symbolic link in UDF is a list of variable-length path @@ -914,6 +931,8 @@ udf_readlink(struct vop_readlink_args *ap) vp = ap->a_vp; node = VTON(vp); len = le64toh(node->fentry->inf_len); + if (len > MAXPATHLEN) + return (EIO); buf = malloc(len, M_DEVBUF, M_WAITOK); iov[0].iov_len = len; iov[0].iov_base = buf; @@ -1116,13 +1135,14 @@ udf_lookup(struct vop_cachedlookup_args *a) struct udf_mnt *udfmp; struct fileid_desc *fid = NULL; struct udf_dirstream *ds; + uint64_t fsize; u_long nameiop; u_long flags; char *nameptr; long namelen; ino_t id = 0; int offset, error = 0; - int fsize, lkflags, ltype, numdirpasses; + int lkflags, ltype, numdirpasses; dvp = a->a_dvp; node = VTON(dvp); @@ -1133,6 +1153,10 @@ udf_lookup(struct vop_cachedlookup_args *a) nameptr = a->a_cnp->cn_nameptr; namelen = a->a_cnp->cn_namelen; fsize = le64toh(node->fentry->inf_len); + if (fsize > INT_MAX) { + /* too big, just cap to INT_MAX */ + fsize = INT_MAX; + } /* * If this is a LOOKUP and we've already partially searched through diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index e7d460af21d4..f577cd07ac7c 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -17,6 +17,8 @@ # in NOTES. # +#NO_UNIVERSE + cpu I486_CPU cpu I586_CPU cpu I686_CPU diff --git a/sys/i386/conf/GENERIC-NODEBUG b/sys/i386/conf/GENERIC-NODEBUG index ea07613a796f..a93304481b5f 100644 --- a/sys/i386/conf/GENERIC-NODEBUG +++ b/sys/i386/conf/GENERIC-NODEBUG @@ -25,6 +25,8 @@ # in NOTES. # +#NO_UNIVERSE + include GENERIC include "std.nodebug" diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 41207eb63cb9..2e947202f723 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -1,3 +1,4 @@ +#NO_UNIVERSE include "../../conf/NOTES" include "../../x86/conf/NOTES" diff --git a/sys/i386/conf/MINIMAL b/sys/i386/conf/MINIMAL index 2a06eb84bff8..8019617ca4d4 100644 --- a/sys/i386/conf/MINIMAL +++ b/sys/i386/conf/MINIMAL @@ -31,6 +31,8 @@ # in NOTES. # +#NO_UNIVERSE + cpu I486_CPU cpu I586_CPU cpu I686_CPU diff --git a/sys/i386/conf/PAE b/sys/i386/conf/PAE index a39d32d77106..72af9e9a9eec 100644 --- a/sys/i386/conf/PAE +++ b/sys/i386/conf/PAE @@ -2,6 +2,8 @@ # PAE -- Generic kernel configuration file for FreeBSD/i386 PAE # +#NO_UNIVERSE + include GENERIC ident PAE-GENERIC diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 465b4d0f365b..b44f5e08bbcf 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -876,14 +876,16 @@ __CONCAT(PMTYPE, init_pat)(void) #ifdef PMAP_PAE_COMP static void * -pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *flags, - int wait) +pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *sflagsp, + int flags) { /* Inform UMA that this allocator uses kernel_map/object. */ - *flags = UMA_SLAB_KERNEL; + *sflagsp = UMA_SLAB_KERNEL; + /* contig allocations cannot be NEVERFREED */ + flags &= ~M_NEVERFREED; return ((void *)kmem_alloc_contig_domainset(DOMAINSET_FIXED(domain), - bytes, wait, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT)); + bytes, flags, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT)); } #endif @@ -5617,6 +5619,8 @@ __CONCAT(PMTYPE, unmapdev)(void *p, vm_size_t size) static void __CONCAT(PMTYPE, page_set_memattr)(vm_page_t m, vm_memattr_t ma) { + if (m->md.pat_mode == ma) + return; m->md.pat_mode = ma; if ((m->flags & PG_FICTITIOUS) != 0) diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 34e71a0665ed..91792430d24c 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -658,7 +658,7 @@ struct sysent sysent[] = { { .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */ { .sy_narg = AS(setcred_args), .sy_call = (sy_call_t *)sys_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = setcred */ - { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ + { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */ }; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index ac4b6ac3f457..a27ab33b34da 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -38,9 +38,11 @@ #include "opt_ddb.h" #include "opt_ktrace.h" +#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC #include <sys/systm.h> #include <sys/capsicum.h> #include <sys/conf.h> +#include <sys/exterrvar.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -478,6 +480,92 @@ kern_fcntl_freebsd(struct thread *td, int fd, int cmd, intptr_t arg) return (error); } +struct flags_trans_elem { + u_int f; + u_int t; +}; + +static u_int +flags_trans(const struct flags_trans_elem *ftes, int nitems, u_int from_flags) +{ + u_int res; + int i; + + res = 0; + for (i = 0; i < nitems; i++) { + if ((from_flags & ftes[i].f) != 0) + res |= ftes[i].t; + } + return (res); +} + +static uint8_t +fd_to_fde_flags(int fd_flags) +{ + static const struct flags_trans_elem fd_to_fde_flags_s[] = { + { .f = FD_CLOEXEC, .t = UF_EXCLOSE }, + { .f = FD_CLOFORK, .t = UF_FOCLOSE }, + { .f = FD_RESOLVE_BENEATH, .t = UF_RESOLVE_BENEATH }, + }; + + return (flags_trans(fd_to_fde_flags_s, nitems(fd_to_fde_flags_s), + fd_flags)); +} + +static int +fde_to_fd_flags(uint8_t fde_flags) +{ + static const struct flags_trans_elem fde_to_fd_flags_s[] = { + { .f = UF_EXCLOSE, .t = FD_CLOEXEC }, + { .f = UF_FOCLOSE, .t = FD_CLOFORK }, + { .f = UF_RESOLVE_BENEATH, .t = FD_RESOLVE_BENEATH }, + }; + + return (flags_trans(fde_to_fd_flags_s, nitems(fde_to_fd_flags_s), + fde_flags)); +} + +static uint8_t +fddup_to_fde_flags(int fddup_flags) +{ + static const struct flags_trans_elem fddup_to_fde_flags_s[] = { + { .f = FDDUP_FLAG_CLOEXEC, .t = UF_EXCLOSE }, + { .f = FDDUP_FLAG_CLOFORK, .t = UF_FOCLOSE }, + }; + + return (flags_trans(fddup_to_fde_flags_s, nitems(fddup_to_fde_flags_s), + fddup_flags)); +} + +static uint8_t +close_range_to_fde_flags(int close_range_flags) +{ + static const struct flags_trans_elem close_range_to_fde_flags_s[] = { + { .f = CLOSE_RANGE_CLOEXEC, .t = UF_EXCLOSE }, + { .f = CLOSE_RANGE_CLOFORK, .t = UF_FOCLOSE }, + }; + + return (flags_trans(close_range_to_fde_flags_s, + nitems(close_range_to_fde_flags_s), close_range_flags)); +} + +static uint8_t +open_to_fde_flags(int open_flags, bool sticky_orb) +{ + static const struct flags_trans_elem open_to_fde_flags_s[] = { + { .f = O_CLOEXEC, .t = UF_EXCLOSE }, + { .f = O_CLOFORK, .t = UF_FOCLOSE }, + { .f = O_RESOLVE_BENEATH, .t = UF_RESOLVE_BENEATH }, + }; +#if defined(__clang__) && __clang_major__ >= 19 + _Static_assert(open_to_fde_flags_s[nitems(open_to_fde_flags_s) - 1].f == + O_RESOLVE_BENEATH, "O_RESOLVE_BENEATH must be last, for sticky_orb"); +#endif + + return (flags_trans(open_to_fde_flags_s, nitems(open_to_fde_flags_s) - + (sticky_orb ? 0 : 1), open_flags)); +} + int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) { @@ -492,6 +580,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) int error, flg, kif_sz, seals, tmp, got_set, got_cleared; uint64_t bsize; off_t foffset; + int flags; error = 0; flg = F_POSIX; @@ -511,6 +600,11 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOEXEC, fd, tmp); break; + case F_DUPFD_CLOFORK: + tmp = arg; + error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOFORK, fd, tmp); + break; + case F_DUP2FD: tmp = arg; error = kern_dup(td, FDDUP_FIXED, 0, fd, tmp); @@ -526,10 +620,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) FILEDESC_SLOCK(fdp); fde = fdeget_noref(fdp, fd); if (fde != NULL) { - td->td_retval[0] = - ((fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0) | - ((fde->fde_flags & UF_RESOLVE_BENEATH) ? - FD_RESOLVE_BENEATH : 0); + td->td_retval[0] = fde_to_fd_flags(fde->fde_flags); error = 0; } FILEDESC_SUNLOCK(fdp); @@ -543,10 +634,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) /* * UF_RESOLVE_BENEATH is sticky and cannot be cleared. */ - fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | - ((arg & FD_CLOEXEC) != 0 ? UF_EXCLOSE : 0) | - ((arg & FD_RESOLVE_BENEATH) != 0 ? - UF_RESOLVE_BENEATH : 0); + fde->fde_flags = (fde->fde_flags & + ~(UF_EXCLOSE | UF_FOCLOSE)) | fd_to_fde_flags(arg); error = 0; } FILEDESC_XUNLOCK(fdp); @@ -916,7 +1005,17 @@ revert_f_setfl: break; default: - error = EINVAL; + if ((cmd & ((1u << F_DUP3FD_SHIFT) - 1)) != F_DUP3FD) + return (EXTERROR(EINVAL, "invalid fcntl cmd")); + /* Handle F_DUP3FD */ + flags = (cmd >> F_DUP3FD_SHIFT); + if ((flags & ~(FD_CLOEXEC | FD_CLOFORK)) != 0) + return (EXTERROR(EINVAL, "invalid flags for F_DUP3FD")); + tmp = arg; + error = kern_dup(td, FDDUP_FIXED, + ((flags & FD_CLOEXEC) != 0 ? FDDUP_FLAG_CLOEXEC : 0) | + ((flags & FD_CLOFORK) != 0 ? FDDUP_FLAG_CLOFORK : 0), + fd, tmp); break; } return (error); @@ -946,7 +1045,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) fdp = p->p_fd; oioctls = NULL; - MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0); + MPASS((flags & ~(FDDUP_FLAG_CLOEXEC | FDDUP_FLAG_CLOFORK)) == 0); MPASS(mode < FDDUP_LASTMODE); AUDIT_ARG_FD(old); @@ -971,8 +1070,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) goto unlock; if (mode == FDDUP_FIXED && old == new) { td->td_retval[0] = new; - if (flags & FDDUP_FLAG_CLOEXEC) - fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; + fdp->fd_ofiles[new].fde_flags |= fddup_to_fde_flags(flags); error = 0; goto unlock; } @@ -1047,10 +1145,8 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) fde_copy(oldfde, newfde); filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps, nioctls); - if ((flags & FDDUP_FLAG_CLOEXEC) != 0) - newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE; - else - newfde->fde_flags = oldfde->fde_flags & ~UF_EXCLOSE; + newfde->fde_flags = (oldfde->fde_flags & ~(UF_EXCLOSE | UF_FOCLOSE)) | + fddup_to_fde_flags(flags); #ifdef CAPABILITIES seqc_write_end(&newfde->fde_seqc); #endif @@ -1416,13 +1512,14 @@ kern_close(struct thread *td, int fd) } static int -close_range_cloexec(struct thread *td, u_int lowfd, u_int highfd) +close_range_flags(struct thread *td, u_int lowfd, u_int highfd, int flags) { struct filedesc *fdp; struct fdescenttbl *fdt; struct filedescent *fde; - int fd; + int fd, fde_flags; + fde_flags = close_range_to_fde_flags(flags); fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); fdt = atomic_load_ptr(&fdp->fd_files); @@ -1434,7 +1531,7 @@ close_range_cloexec(struct thread *td, u_int lowfd, u_int highfd) for (; fd <= highfd; fd++) { fde = &fdt->fdt_ofiles[fd]; if (fde->fde_file != NULL) - fde->fde_flags |= UF_EXCLOSE; + fde->fde_flags |= fde_flags; } out_locked: FILEDESC_XUNLOCK(fdp); @@ -1492,8 +1589,8 @@ kern_close_range(struct thread *td, int flags, u_int lowfd, u_int highfd) return (EINVAL); } - if ((flags & CLOSE_RANGE_CLOEXEC) != 0) - return (close_range_cloexec(td, lowfd, highfd)); + if ((flags & (CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_CLOFORK)) != 0) + return (close_range_flags(td, lowfd, highfd, flags)); return (close_range_impl(td, lowfd, highfd)); } @@ -1513,7 +1610,7 @@ sys_close_range(struct thread *td, struct close_range_args *uap) AUDIT_ARG_CMD(uap->highfd); AUDIT_ARG_FFLAGS(uap->flags); - if ((uap->flags & ~(CLOSE_RANGE_CLOEXEC)) != 0) + if ((uap->flags & ~(CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_CLOFORK)) != 0) return (EINVAL); return (kern_close_range(td, uap->flags, uap->lowfd, uap->highfd)); } @@ -2171,8 +2268,7 @@ _finstall(struct filedesc *fdp, struct file *fp, int fd, int flags, seqc_write_begin(&fde->fde_seqc); #endif fde->fde_file = fp; - fde->fde_flags = ((flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0) | - ((flags & O_RESOLVE_BENEATH) != 0 ? UF_RESOLVE_BENEATH : 0); + fde->fde_flags = open_to_fde_flags(flags, true); if (fcaps != NULL) filecaps_move(fcaps, &fde->fde_caps); else @@ -2432,6 +2528,7 @@ fdcopy(struct filedesc *fdp) newfdp->fd_freefile = fdp->fd_freefile; FILEDESC_FOREACH_FDE(fdp, i, ofde) { if ((ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0 || + (ofde->fde_flags & UF_FOCLOSE) != 0 || !fhold(ofde->fde_file)) { if (newfdp->fd_freefile == fdp->fd_freefile) newfdp->fd_freefile = i; @@ -2729,6 +2826,12 @@ fdcloseexec(struct thread *td) fdfree(fdp, i); (void) closefp(fdp, i, fp, td, false, false); FILEDESC_UNLOCK_ASSERT(fdp); + } else if (fde->fde_flags & UF_FOCLOSE) { + /* + * https://austingroupbugs.net/view.php?id=1851 + * FD_CLOFORK should not be preserved across exec + */ + fde->fde_flags &= ~UF_FOCLOSE; } } } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index a61ebfc5c7c8..5d51aa675cb7 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1050,8 +1050,7 @@ osigaction(struct thread *td, struct osigaction_args *uap) int osigreturn(struct thread *td, struct osigreturn_args *uap) { - - return (nosys(td, (struct nosys_args *)uap)); + return (kern_nosys(td, 0)); } #endif #endif /* COMPAT_43 */ @@ -4288,6 +4287,12 @@ struct nosys_args { int nosys(struct thread *td, struct nosys_args *args) { + return (kern_nosys(td, args->dummy)); +} + +int +kern_nosys(struct thread *td, int dummy) +{ struct proc *p; p = td->td_proc; diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c index 24406763a93a..a93d711e7597 100644 --- a/sys/kern/kern_syscalls.c +++ b/sys/kern/kern_syscalls.c @@ -35,6 +35,7 @@ #include <sys/resourcevar.h> #include <sys/sx.h> #include <sys/syscall.h> +#include <sys/syscallsubr.h> #include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/systm.h> @@ -50,14 +51,14 @@ int lkmnosys(struct thread *td, struct nosys_args *args) { - return (nosys(td, args)); + return (kern_nosys(td, 0)); } int lkmressys(struct thread *td, struct nosys_args *args) { - return (nosys(td, args)); + return (kern_nosys(td, 0)); } struct sysent nosys_sysent = { diff --git a/sys/kern/subr_asan.c b/sys/kern/subr_asan.c index 0edb631d1475..464efda1e91a 100644 --- a/sys/kern/subr_asan.c +++ b/sys/kern/subr_asan.c @@ -263,8 +263,7 @@ kasan_mark(const void *addr, size_t size, size_t redzsize, uint8_t code) if (__predict_false(!kasan_enabled)) return; - if ((vm_offset_t)addr >= DMAP_MIN_ADDRESS && - (vm_offset_t)addr < DMAP_MAX_ADDRESS) + if (kasan_md_unsupported((vm_offset_t)addr)) return; KASSERT((vm_offset_t)addr >= VM_MIN_KERNEL_ADDRESS && diff --git a/sys/kern/subr_pctrie.c b/sys/kern/subr_pctrie.c index 3a3548bad52b..bb86c779b936 100644 --- a/sys/kern/subr_pctrie.c +++ b/sys/kern/subr_pctrie.c @@ -691,21 +691,23 @@ _pctrie_lookup_ge(struct pctrie *ptree, struct pctrie_node *node, */ if (node == PCTRIE_NULL || *pctrie_toval(node) < index) { /* Climb the path to find a node with a descendant > index. */ - for (node = parent; node != NULL; node = pctrie_parent(node)) { - slot = pctrie_slot(node, index) + 1; - if ((node->pn_popmap >> slot) != 0) + node = NULL; + while (parent != NULL) { + slot = pctrie_slot(parent, index) + 1; + if ((parent->pn_popmap >> slot) != 0) break; + node = parent; + parent = pctrie_parent(node); } - if (node == NULL) { + if (parent == NULL) { if (parent_out != NULL) - *parent_out = NULL; + *parent_out = node; return (NULL); } /* Step to the least child with a descendant > index. */ - slot += ffs(node->pn_popmap >> slot) - 1; - parent = node; - node = pctrie_node_load(&node->pn_child[slot], NULL, + slot += ffs(parent->pn_popmap >> slot) - 1; + node = pctrie_node_load(&parent->pn_child[slot], NULL, PCTRIE_LOCKED); } /* Descend to the least leaf of the subtrie. */ @@ -785,21 +787,23 @@ _pctrie_lookup_le(struct pctrie *ptree, struct pctrie_node *node, */ if (node == PCTRIE_NULL || *pctrie_toval(node) > index) { /* Climb the path to find a node with a descendant < index. */ - for (node = parent; node != NULL; node = pctrie_parent(node)) { - slot = pctrie_slot(node, index); - if ((node->pn_popmap & ((1 << slot) - 1)) != 0) + node = NULL; + while (parent != NULL) { + slot = pctrie_slot(parent, index); + if ((parent->pn_popmap & ((1 << slot) - 1)) != 0) break; + node = parent; + parent = pctrie_parent(node); } - if (node == NULL) { + if (parent == NULL) { if (parent_out != NULL) - *parent_out = NULL; + *parent_out = node; return (NULL); } /* Step to the greatest child with a descendant < index. */ - slot = ilog2(node->pn_popmap & ((1 << slot) - 1)); - parent = node; - node = pctrie_node_load(&node->pn_child[slot], NULL, + slot = ilog2(parent->pn_popmap & ((1 << slot) - 1)); + node = pctrie_node_load(&parent->pn_child[slot], NULL, PCTRIE_LOCKED); } /* Descend to the greatest leaf of the subtrie. */ diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 18388ae5f232..bac7d0080c71 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -338,8 +338,9 @@ ast_handler(struct thread *td, struct trapframe *framep, bool dtor) td->td_ast = 0; } - CTR3(KTR_SYSC, "ast: thread %p (pid %d, %s)", td, td->td_proc->p_pid, - td->td_proc->p_comm); + CTR3(KTR_SYSC, "ast: thread %p (pid %d, %s)", td, + td->td_proc == NULL ? -1 : td->td_proc->p_pid, + td->td_proc == NULL ? "" : td->td_proc->p_comm); KASSERT(framep == NULL || TRAPF_USERMODE(framep), ("ast in kernel mode")); diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 94e44d888181..b472aaea89e6 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -2309,6 +2309,12 @@ sys_exterrctl(struct thread *td, struct exterrctl_args *uap) return (EINVAL); td->td_pflags2 &= ~TDP2_UEXTERR; return (0); + case EXTERRCTL_UD: + /* + * Important: this code must always return EINVAL and never any + * extended error, for testing purposes. + */ + /* FALLTHROUGH */ default: return (EINVAL); } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 9340779918a2..ed651da96b14 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -548,7 +548,7 @@ sys_pipe2(struct thread *td, struct pipe2_args *uap) { int error, fildes[2]; - if (uap->flags & ~(O_CLOEXEC | O_NONBLOCK)) + if ((uap->flags & ~(O_CLOEXEC | O_CLOFORK | O_NONBLOCK)) != 0) return (EINVAL); error = kern_pipe(td, fildes, uap->flags, NULL, NULL); if (error) diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 2ab17e036d5c..90559fab6086 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3349,7 +3349,7 @@ size_t size ); } -592 AUE_NULL STD { +592 AUE_NULL STD|CAPENABLED { int exterrctl( u_int op, u_int flags, diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index 11141d197aec..a545a0a54c25 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -1724,7 +1724,7 @@ freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap) return (sys_msgsys(td, (struct msgsys_args *)uap)); } #else - return (nosys(td, NULL)); + return (kern_nosys(td, 0)); #endif } diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index e399517010fc..a99e1a4de14e 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -1904,7 +1904,7 @@ freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) return (sys_semsys(td, (struct semsys_args *)uap)); } #else - return (nosys(td, NULL)); + return (kern_nosys(td, 0)); #endif } diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index 60e3fe92a4b7..8d1a469127c6 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -1474,7 +1474,7 @@ freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap) return (EINVAL); } #else - return (nosys(td, NULL)); + return (kern_nosys(td, 0)); #endif } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index ad8485028987..133724ac76c5 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -151,6 +151,10 @@ kern_socket(struct thread *td, int domain, int type, int protocol) type &= ~SOCK_CLOEXEC; oflag |= O_CLOEXEC; } + if ((type & SOCK_CLOFORK) != 0) { + type &= ~SOCK_CLOFORK; + oflag |= O_CLOFORK; + } if ((type & SOCK_NONBLOCK) != 0) { type &= ~SOCK_NONBLOCK; fflag |= FNONBLOCK; @@ -352,7 +356,8 @@ kern_accept4(struct thread *td, int s, struct sockaddr *sa, int flags, goto done; #endif error = falloc_caps(td, &nfp, &fd, - (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps); + ((flags & SOCK_CLOEXEC) != 0 ? O_CLOEXEC : 0) | + ((flags & SOCK_CLOFORK) != 0 ? O_CLOFORK : 0), &fcaps); if (error != 0) goto done; SOCK_LOCK(head); @@ -435,7 +440,7 @@ int sys_accept4(struct thread *td, struct accept4_args *uap) { - if (uap->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) + if ((uap->flags & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK)) != 0) return (EINVAL); return (accept1(td, uap->s, uap->name, uap->anamelen, uap->flags)); @@ -557,6 +562,10 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol, type &= ~SOCK_CLOEXEC; oflag |= O_CLOEXEC; } + if ((type & SOCK_CLOFORK) != 0) { + type &= ~SOCK_CLOFORK; + oflag |= O_CLOFORK; + } if ((type & SOCK_NONBLOCK) != 0) { type &= ~SOCK_NONBLOCK; fflag |= FNONBLOCK; diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 72bd0246db11..0056dac65c7d 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -3463,7 +3463,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) UNP_LINK_UNLOCK_ASSERT(); - fdflags = (flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0; + fdflags = ((flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0) | + ((flags & MSG_CMSG_CLOFORK) ? O_CLOFORK : 0); error = 0; if (controlp != NULL) /* controlp == NULL => free control messages */ diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index d7c23122b4d8..02973146068d 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -301,7 +301,7 @@ static TAILQ_HEAD(,kaiocb) aio_jobs; /* (c) Async job list */ static struct unrhdr *aiod_unr; static void aio_biocleanup(struct bio *bp); -static void aio_init_aioinfo(struct proc *p); +static int aio_init_aioinfo(struct proc *p); static int aio_onceonly(void); static int aio_free_entry(struct kaiocb *job); static void aio_process_rw(struct kaiocb *job); @@ -422,10 +422,11 @@ aio_onceonly(void) * Init the per-process aioinfo structure. The aioinfo limits are set * per-process for user limit (resource) management. */ -static void +static int aio_init_aioinfo(struct proc *p) { struct kaioinfo *ki; + int error; ki = uma_zalloc(kaio_zone, M_WAITOK); mtx_init(&ki->kaio_mtx, "aiomtx", NULL, MTX_DEF | MTX_NEW); @@ -451,8 +452,20 @@ aio_init_aioinfo(struct proc *p) uma_zfree(kaio_zone, ki); } - while (num_aio_procs < MIN(target_aio_procs, max_aio_procs)) - aio_newproc(NULL); + error = 0; + while (num_aio_procs < MIN(target_aio_procs, max_aio_procs)) { + error = aio_newproc(NULL); + if (error != 0) { + /* + * At least one worker is enough to have AIO + * functional. Clear error in that case. + */ + if (num_aio_procs > 0) + error = 0; + break; + } + } + return (error); } static int @@ -1490,8 +1503,11 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj, int fd, kqfd; u_short evflags; - if (p->p_aioinfo == NULL) - aio_init_aioinfo(p); + if (p->p_aioinfo == NULL) { + error = aio_init_aioinfo(p); + if (error != 0) + goto err1; + } ki = p->p_aioinfo; @@ -2213,8 +2229,11 @@ kern_lio_listio(struct thread *td, int mode, struct aiocb * const *uacb_list, if (nent < 0 || nent > max_aio_queue_per_proc) return (EINVAL); - if (p->p_aioinfo == NULL) - aio_init_aioinfo(p); + if (p->p_aioinfo == NULL) { + error = aio_init_aioinfo(p); + if (error != 0) + return (error); + } ki = p->p_aioinfo; @@ -2503,8 +2522,11 @@ kern_aio_waitcomplete(struct thread *td, struct aiocb **ujobp, timo = tvtohz(&atv); } - if (p->p_aioinfo == NULL) - aio_init_aioinfo(p); + if (p->p_aioinfo == NULL) { + error = aio_init_aioinfo(p); + if (error != 0) + return (error); + } ki = p->p_aioinfo; error = 0; diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 3d455b3874cc..89c1d779f04c 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -332,7 +332,8 @@ SDT_PROBE_DEFINE2(vfs, namecache, evict_negative, done, "struct vnode *", "char *"); SDT_PROBE_DEFINE1(vfs, namecache, symlink, alloc__fail, "size_t"); -SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata", "int", "bool"); +SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata *", "int", + "enum cache_fpl_status"); SDT_PROBE_DECLARE(vfs, namei, lookup, entry); SDT_PROBE_DECLARE(vfs, namei, lookup, return); @@ -6420,15 +6421,11 @@ out: cache_fpl_smr_assert_not_entered(&fpl); cache_fpl_assert_status(&fpl); *status = fpl.status; - if (SDT_PROBES_ENABLED()) { - SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status); - if (fpl.status == CACHE_FPL_STATUS_HANDLED) - SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true, - ndp); - } - + SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status); if (__predict_true(fpl.status == CACHE_FPL_STATUS_HANDLED)) { MPASS(error != CACHE_FPL_FAILED); + SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true, + ndp); if (error != 0) { cache_fpl_cleanup_cnp(fpl.cnp); MPASS(fpl.dvp == NULL); diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 2a01ec1e307e..fd6202a1424c 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -456,6 +456,7 @@ vop_stdpathconf(struct vop_pathconf_args *ap) case _PC_MAC_PRESENT: case _PC_NAMEDATTR_ENABLED: case _PC_HAS_NAMEDATTR: + case _PC_HAS_HIDDENSYSTEM: *ap->a_retval = 0; return (0); default: diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c index 9562350c897f..2b42228465a4 100644 --- a/sys/kern/vfs_inotify.c +++ b/sys/kern/vfs_inotify.c @@ -503,7 +503,7 @@ inotify_can_coalesce(struct inotify_softc *sc, struct inotify_event *evp) return (prev != NULL && prev->ev.mask == evp->mask && prev->ev.wd == evp->wd && prev->ev.cookie == evp->cookie && prev->ev.len == evp->len && - (evp->len == 0 || strcmp(prev->ev.name, evp->name) == 0)); + memcmp(prev->ev.name, evp->name, evp->len) == 0); } static void @@ -760,9 +760,11 @@ vn_inotify_add_watch(struct vnode *vp, struct inotify_softc *sc, uint32_t mask, * directory if it's specified as a vnode. */ vrefact(vp); + VOP_UNLOCK(vp); NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, dp->d_name, vp); error = namei(&nd); + vn_lock(vp, LK_SHARED | LK_RETRY); if (error != 0) break; vn_irflag_set_cond(nd.ni_vp, VIRF_INOTIFY_PARENT); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index d880733cbfe7..c71e0d9ee569 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -4314,10 +4314,6 @@ kern_getdirentries(struct thread *td, int fd, char *buf, size_t count, vp = fp->f_vnode; foffset = foffset_lock(fp, 0); unionread: - if (vp->v_type != VDIR) { - error = EINVAL; - goto fail; - } if (__predict_false((vp->v_vflag & VV_UNLINKED) != 0)) { error = ENOENT; goto fail; @@ -4330,6 +4326,19 @@ unionread: auio.uio_segflg = bufseg; auio.uio_td = td; vn_lock(vp, LK_SHARED | LK_RETRY); + /* + * We want to return ENOTDIR for anything that is not VDIR, but + * not for VBAD, and we can't check for VBAD while the vnode is + * unlocked. + */ + if (vp->v_type != VDIR) { + if (vp->v_type == VBAD) + error = EBADF; + else + error = ENOTDIR; + VOP_UNLOCK(vp); + goto fail; + } AUDIT_ARG_VNODE1(vp); loff = auio.uio_offset = foffset; #ifdef MAC diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 9922796f8a1d..7cb6e2124326 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -326,6 +326,7 @@ SUBDIR= \ proto \ pseudofs \ ${_pst} \ + ${_pt} \ pty \ puc \ pwm \ @@ -842,6 +843,7 @@ _iwx= iwx _ixl= ixl _nvdimm= nvdimm _pms= pms +_pt= pt _qat= qat .if ${MK_SOURCELESS_UCODE} != "no" _qatfw= qatfw diff --git a/sys/modules/pt/Makefile b/sys/modules/pt/Makefile new file mode 100644 index 000000000000..416b072face9 --- /dev/null +++ b/sys/modules/pt/Makefile @@ -0,0 +1,8 @@ + +.PATH: ${SRCTOP}/sys/amd64/pt + +KMOD= pt +SRCS= pt.c pt.h device_if.h bus_if.h +SRCS+= opt_hwpmc_hooks.h opt_kstack_pages.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/qlnx/qlnxe/Makefile b/sys/modules/qlnx/qlnxe/Makefile index 3d8415cf0e57..2a44ae6ddde5 100644 --- a/sys/modules/qlnx/qlnxe/Makefile +++ b/sys/modules/qlnx/qlnxe/Makefile @@ -58,6 +58,7 @@ SRCS+=qlnx_rdma.c SRCS+=qlnx_ioctl.c SRCS+=qlnx_os.c +SRCS+=opt_inet.h SRCS+= ${LINUXKPI_GENSRCS} diff --git a/sys/modules/sound/sound/Makefile b/sys/modules/sound/sound/Makefile index d2cfed2f4b6a..f3978e9bd9cc 100644 --- a/sys/modules/sound/sound/Makefile +++ b/sys/modules/sound/sound/Makefile @@ -13,11 +13,11 @@ SRCS+= feeder.c feeder_rate.c feeder_volume.c SRCS+= feeder_chain.c feeder_eq.c feeder_format.c SRCS+= feeder_matrix.c feeder_mixer.c SRCS+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h -SRCS+= mpu_if.h mpufoi_if.h synth_if.h -SRCS+= mpu_if.c mpufoi_if.c synth_if.c +SRCS+= mpu_if.h mpufoi_if.h +SRCS+= mpu_if.c mpufoi_if.c SRCS+= ac97.c buffer.c channel.c dsp.c SRCS+= mixer.c sndstat.c sound.c vchan.c -SRCS+= midi.c mpu401.c sequencer.c +SRCS+= midi.c mpu401.c feeder_eq_gen.h: ${SYSDIR}/tools/sound/feeder_eq_mkfilter.awk ${AWK} -f ${SYSDIR}/tools/sound/feeder_eq_mkfilter.awk -- ${FEEDER_EQ_PRESETS} > ${.TARGET} diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h index cf4f75bd0b6c..01485cf26e06 100644 --- a/sys/net/ethernet.h +++ b/sys/net/ethernet.h @@ -62,6 +62,8 @@ struct ether_header { u_char ether_shost[ETHER_ADDR_LEN]; u_short ether_type; } __packed; +_Static_assert(sizeof(struct ether_header) == ETHER_HDR_LEN, + "size of struct ether_header is wrong"); /* * Structure of a 48-bit Ethernet address. @@ -69,6 +71,8 @@ struct ether_header { struct ether_addr { u_char octet[ETHER_ADDR_LEN]; } __packed; +_Static_assert(sizeof(struct ether_addr) == ETHER_ADDR_LEN, + "size of struct ether_addr is wrong"); #define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ #define ETHER_IS_IPV6_MULTICAST(addr) \ @@ -112,6 +116,8 @@ struct ether_vlan_header { uint16_t evl_tag; uint16_t evl_proto; } __packed; +_Static_assert(sizeof(struct ether_vlan_header) == ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN, + "size of struct ether_vlan_header is wrong"); #define EVL_VLID_MASK 0x0FFF #define EVL_PRI_MASK 0xE000 diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 7be4dfac23e7..3ae0c01c0efc 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -92,11 +92,6 @@ #include <crypto/sha1.h> -#ifdef CTASSERT -CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2); -CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); -#endif - VNET_DEFINE(pfil_head_t, link_pfil_head); /* Packet filter hooks */ /* netgraph node hooks for ng_ether(4) */ diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index 9867a718e148..5b52bfa80e3b 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -718,6 +718,7 @@ lagg_capabilities(struct lagg_softc *sc) sc->sc_ifp->if_capenable = ena; sc->sc_ifp->if_capenable2 = ena2; sc->sc_ifp->if_hwassist = hwa; + (void)if_hw_tsomax_update(sc->sc_ifp, &hw_tsomax); getmicrotime(&sc->sc_ifp->if_lastchange); if (sc->sc_ifflags & IFF_DEBUG) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 1416f0c2cdbe..452a8eb4024b 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -551,6 +551,9 @@ extern struct sx pf_end_lock; #endif /* PF_INET_INET6 */ #ifdef _KERNEL + +void unhandled_af(int) __dead2; + static void inline pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af) { @@ -565,6 +568,8 @@ pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af) memcpy(&dst->v6, &src->v6, sizeof(dst->v6)); break; #endif /* INET6 */ + default: + unhandled_af(af); } } #endif @@ -1365,7 +1370,6 @@ struct pf_kruleset { struct pf_krulequeue queues[2]; struct { struct pf_krulequeue *ptr; - struct pf_krule **ptr_array; u_int32_t rcount; u_int32_t ticket; int open; @@ -2300,7 +2304,6 @@ VNET_DECLARE(struct pf_krule *, pf_rulemarker); #define V_pf_rulemarker VNET(pf_rulemarker) #endif -void unhandled_af(int) __dead2; int pf_start(void); int pf_stop(void); void pf_initialize(void); @@ -2496,7 +2499,7 @@ int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, u_int64_t, int, int, int); int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t, - pf_addr_filter_func_t); + pf_addr_filter_func_t, bool); void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *); struct pfr_ktable * pfr_attach_table(struct pf_kruleset *, char *); @@ -2530,6 +2533,8 @@ int pfr_ina_rollback(struct pfr_table *, u_int32_t, int *, int); int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int); int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, int *, u_int32_t, int); +struct pfr_ktable + *pfr_ktable_select_active(struct pfr_ktable *); MALLOC_DECLARE(PFI_MTYPE); VNET_DECLARE(struct pfi_kkif *, pfi_all); @@ -2670,6 +2675,7 @@ int pf_ioctl_get_addrs(struct pf_nl_pooladdr *); int pf_ioctl_get_addr(struct pf_nl_pooladdr *); int pf_ioctl_get_rulesets(struct pfioc_ruleset *); int pf_ioctl_get_ruleset(struct pfioc_ruleset *); +int pf_ioctl_natlook(struct pfioc_natlook *); void pf_krule_free(struct pf_krule *); void pf_krule_clear_counters(struct pf_krule *); @@ -2707,7 +2713,6 @@ u_short pf_map_addr(u_int8_t, struct pf_krule *, u_short pf_map_addr_sn(u_int8_t, struct pf_krule *, struct pf_addr *, struct pf_addr *, struct pfi_kkif **nkif, struct pf_addr *, - struct pf_ksrc_node **, struct pf_srchash **, struct pf_kpool *, pf_sn_types_t); int pf_get_transaddr_af(struct pf_krule *, struct pf_pdesc *); diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index c5a478533313..9074878e17e4 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -2214,12 +2214,9 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, /* VHT */ if (IEEE80211_IS_CHAN_VHT(ni->ni_chan) && - vhtcap != NULL && - vhtinfo != NULL) { - /* XXX TODO; see below */ - net80211_vap_printf(vap, "%s: VHT TODO!\n", __func__); + vhtcap != NULL) { ieee80211_vht_node_init(ni); - ieee80211_vht_update_cap(ni, vhtcap, vhtinfo); + ieee80211_vht_update_cap(ni, vhtcap); } else if (ni->ni_flags & IEEE80211_NODE_VHT) ieee80211_vht_node_cleanup(ni); diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 5ec80e3646b8..c28f124648a1 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -1952,6 +1952,11 @@ do { \ _RETURN_CHAN_BITS(0); /* + * TODO: should we bail out if there's no htinfo? + * Or just treat it as if we can't do the HT20/HT40 check? + */ + + /* * The original code was based on * 802.11ac-2013, Table 8-183x-VHT Operation Information subfields. * 802.11-2020, Table 9-274-VHT Operation Information subfields @@ -1962,8 +1967,12 @@ do { \ */ htinfo = (const struct ieee80211_ie_htinfo *)ni->ni_ies.htinfo_ie; - ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) == - IEEE80211_HTINFO_TXWIDTH_2040); + if (htinfo != NULL) + ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) == + IEEE80211_HTINFO_TXWIDTH_2040); + else + ht40 = false; + can_vht160 = can_vht80p80 = can_vht80 = false; /* 20 Mhz */ diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index ad17af6778a1..a201d1b278f0 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -3138,6 +3138,36 @@ ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) } /** + * @brief Increment the given TID TX sequence, return the current one. + * + * @param ni ieee80211_node to operate on + * @param tid TID, or IEEE80211_NONQOS_TID + * @returns sequence number, from 0 .. 4095 inclusive, post increments + */ +ieee80211_seq ieee80211_tx_seqno_fetch_incr(struct ieee80211_node *ni, + uint8_t tid) +{ + ieee80211_seq seq; + + seq = ni->ni_txseqs[tid]; + ni->ni_txseqs[tid] = (ni->ni_txseqs[tid] + 1) % IEEE80211_SEQ_RANGE; + return (seq); +} + +/** + * @brief Return the current sequence number for the given TID + * + * @param ni ieee80211_node to operate on + * @param tid TID, or IEEE80211_NONQOS_TID + * @returns sequence number, from 0 .. 4095 inclusive + */ +ieee80211_seq ieee80211_tx_seqno_fetch(const struct ieee80211_node *ni, + uint8_t tid) +{ + return (ni->ni_txseqs[tid]); +} + +/** * @brief return a dot11rate / ratecode representing the current transmit rate * * This is the API call for legacy / 802.11n drivers and rate control APIs diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index c83eee04a8dc..ef25fa0d7fdd 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -531,6 +531,12 @@ void ieee80211_node_leave(struct ieee80211_node *); int8_t ieee80211_getrssi(struct ieee80211vap *); void ieee80211_getsignal(struct ieee80211vap *, int8_t *, int8_t *); +/* TX sequence space related routines */ +ieee80211_seq ieee80211_tx_seqno_fetch_incr(struct ieee80211_node *, + uint8_t); +ieee80211_seq ieee80211_tx_seqno_fetch(const struct ieee80211_node *, + uint8_t); + /* * Node transmit rate specific manipulation. * diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index a4151f807882..afe83ea0805c 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -4195,17 +4195,15 @@ ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) * Check the frame type and TID and assign a suitable sequence number * from the correct sequence number space. * + * This implements the components of 802.11-2020 10.3.2.14.2 + * (Transmitter Requirements) that net80211 currently supports. + * * It assumes the mbuf has been encapsulated, and has the TID assigned * if it is a QoS frame. * * Note this also clears any existing fragment ID in the header, so it * must be called first before assigning fragment IDs. * - * For now this implements parts of 802.11-2012; it doesn't do all of - * the needed checks for full compliance (notably QoS-Data NULL frames). - * - * TODO: update to 802.11-2020 10.3.2.14.2 (Transmitter Requirements) - * * @param ni ieee80211_node this frame will be transmitted to * @param arg_tid A temporary check, existing callers may set * this to a TID variable they were using, and this routine @@ -4239,16 +4237,30 @@ ieee80211_output_seqno_assign(struct ieee80211_node *ni, int arg_tid, "%s: called; TID mismatch; tid=%u, arg_tid=%d\n", __func__, tid, arg_tid); - if (IEEE80211_HAS_SEQ(type, subtype)) { - /* - * 802.11-2012 9.3.2.10 - QoS multicast frames - * come out of a different seqno space. - */ - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; - else - seqno = ni->ni_txseqs[tid]++; - } else + + /* 802.11-2020 10.3.2.14.2 (Transmitter Requirements) sections */ + + /* SNS7 - unicast PV1 management frame */ + + /* SNS6 - unicast PV1 data frame */ + + /* SNS5 - QoS NULL frames */ + if (IEEE80211_QOS_HAS_SEQ(wh) && IEEE80211_IS_QOS_NULL(wh)) + seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID); + + /* SNS4 - QMF STA transmitting a QMF */ + + /* SNS3 - QoS STA; Time Priority Management frame */ + + /* SNS2 - unicast QoS STA, data frame, excluding SNS5 */ + else if (IEEE80211_QOS_HAS_SEQ(wh) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) + seqno = ieee80211_tx_seqno_fetch_incr(ni, tid); + + /* SNS1 - Baseline (everything else) */ + else if (IEEE80211_HAS_SEQ(type, subtype)) + seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID); + else seqno = 0; /* @@ -4276,7 +4288,7 @@ ieee80211_output_beacon_seqno_assign(struct ieee80211_node *ni, struct mbuf *m) wh = mtod(m, struct ieee80211_frame *); - seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID); *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); M_SEQNO_SET(m, seqno); diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c index e91977f1ef98..de0b691d4d2a 100644 --- a/sys/net80211/ieee80211_vht.c +++ b/sys/net80211/ieee80211_vht.c @@ -838,12 +838,10 @@ ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *ni) } void -ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie, - const uint8_t *vhtop_ie) +ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie) { ieee80211_parse_vhtcap(ni, vhtcap_ie); - ieee80211_parse_vhtopmode(ni, vhtop_ie); } static struct ieee80211_channel * diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h index 2964de63c343..a1529df4a85b 100644 --- a/sys/net80211/ieee80211_vht.h +++ b/sys/net80211/ieee80211_vht.h @@ -52,8 +52,7 @@ uint8_t * ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *); uint8_t *ieee80211_add_vhtcap_ch(uint8_t *, struct ieee80211vap *, struct ieee80211_channel *); -void ieee80211_vht_update_cap(struct ieee80211_node *, - const uint8_t *, const uint8_t *); +void ieee80211_vht_update_cap(struct ieee80211_node *, const uint8_t *); struct ieee80211_channel * ieee80211_vht_adjust_channel(struct ieee80211com *, diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index bccd4b84561a..dbe48242381d 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1745,6 +1745,23 @@ in_pcbrele(struct inpcb *inp, const inp_lookup_t lock) } /* + * Dereference and rlock inp, for which the caller must own the + * reference. Returns true if inp no longer usable, false otherwise. + */ +bool +in_pcbrele_rlock(struct inpcb *inp) +{ + INP_RLOCK(inp); + if (in_pcbrele_rlocked(inp)) + return (true); + if ((inp->inp_flags & INP_FREED) != 0) { + INP_RUNLOCK(inp); + return (true); + } + return (false); +} + +/* * Unconditionally schedule an inpcb to be freed by decrementing its * reference count, which should occur only after the inpcb has been detached * from its socket. If another thread holds a temporary reference (acquired diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 57cf15ca37fc..9e0618e87601 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -681,6 +681,7 @@ void in_pcbref(struct inpcb *); bool in_pcbrele(struct inpcb *, inp_lookup_t); bool in_pcbrele_rlocked(struct inpcb *); bool in_pcbrele_wlocked(struct inpcb *); +bool in_pcbrele_rlock(struct inpcb *inp); typedef bool inp_match_t(const struct inpcb *, void *); struct inpcb_iterator { diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index cd42a67294a6..db415f6bdf03 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2720,9 +2720,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys) ksr->snd_tag->sw->snd_tag_status_str != NULL) { sz = SND_TAG_STATUS_MAXLEN; - ksr->snd_tag->sw->snd_tag_status_str( + in_pcbref(inp); + INP_RUNLOCK(inp); + error = ksr->snd_tag->sw-> + snd_tag_status_str( ksr->snd_tag, NULL, &sz); - len += sz; + if (in_pcbrele_rlock(inp)) + return (EDEADLK); + if (error == 0) + len += sz; } } kss = so->so_snd.sb_tls_info; @@ -2739,9 +2745,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys) kss->snd_tag->sw->snd_tag_status_str != NULL) { sz = SND_TAG_STATUS_MAXLEN; - kss->snd_tag->sw->snd_tag_status_str( + in_pcbref(inp); + INP_RUNLOCK(inp); + error = kss->snd_tag->sw-> + snd_tag_status_str( kss->snd_tag, NULL, &sz); - len += sz; + if (in_pcbrele_rlock(inp)) + return (EDEADLK); + if (error == 0) + len += sz; } } if (p) { @@ -2811,9 +2823,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys) if (ksr->snd_tag != NULL && ksr->snd_tag->sw->snd_tag_status_str != NULL) { sz = SND_TAG_STATUS_MAXLEN; - ksr->snd_tag->sw->snd_tag_status_str( + in_pcbref(inp); + INP_RUNLOCK(inp); + error = ksr->snd_tag->sw->snd_tag_status_str( ksr->snd_tag, buf + len, &sz); - len += sz; + if (in_pcbrele_rlock(inp)) + return (EDEADLK); + if (error == 0) { + xktls->rcv.drv_st_len = sz; + len += sz; + } } } if (kss != NULL && kss->gen == xig.xig_gen) { @@ -2828,9 +2847,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys) if (kss->snd_tag != NULL && kss->snd_tag->sw->snd_tag_status_str != NULL) { sz = SND_TAG_STATUS_MAXLEN; - kss->snd_tag->sw->snd_tag_status_str( + in_pcbref(inp); + INP_RUNLOCK(inp); + error = kss->snd_tag->sw->snd_tag_status_str( kss->snd_tag, buf + len, &sz); - len += sz; + if (in_pcbrele_rlock(inp)) + return (EDEADLK); + if (error == 0) { + xktls->snd.drv_st_len = sz; + len += sz; + } } } len = roundup2(len, __alignof(*xktls)); @@ -2858,12 +2884,23 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys) static int tcp_ktlslist1(SYSCTL_HANDLER_ARGS, bool export_keys) { - int res; - - sx_xlock(&ktlslist_lock); - res = tcp_ktlslist_locked(oidp, arg1, arg2, req, export_keys); - sx_xunlock(&ktlslist_lock); - return (res); + int repeats, error; + + for (repeats = 0; repeats < 100; repeats++) { + if (sx_xlock_sig(&ktlslist_lock)) + return (EINTR); + error = tcp_ktlslist_locked(oidp, arg1, arg2, req, + export_keys); + sx_xunlock(&ktlslist_lock); + if (error != EDEADLK) + break; + if (sig_intr() != 0) { + error = EINTR; + break; + } + req->oldidx = 0; + } + return (error); } static int diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 3ea561e63503..687b0d538666 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1520,7 +1520,8 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr_in6 *sin6, struct thread *td) INP_WLOCK_ASSERT(inp); if (__predict_false((so->so_state & - (SS_ISCONNECTING | SS_ISCONNECTED)) != 0)) + (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING | + SS_ISDISCONNECTED)) != 0)) return (EISCONN); if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0)) return (EOPNOTSUPP); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 0379ef7c789a..c90a1213bd66 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -765,8 +765,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) } if (ifa != NULL && ((struct in6_ifaddr *)ifa)->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| - IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { + (IN6_IFF_NOTREADY|IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { NET_EPOCH_EXIT(et); return (EADDRNOTAVAIL); } diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h index 8492ecb3021b..720317ed74f3 100644 --- a/sys/netlink/netlink_message_parser.h +++ b/sys/netlink/netlink_message_parser.h @@ -209,7 +209,8 @@ int nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt, int nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target); -bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...); +bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...) + __printflike(2, 3); #define NLMSG_REPORT_ERR_MSG(_npt, _fmt, ...) { \ nlmsg_report_err_msg(_npt, _fmt, ## __VA_ARGS__); \ diff --git a/sys/netpfil/ipfilter/netinet/fil.c b/sys/netpfil/ipfilter/netinet/fil.c index 2a75190a3ec7..2fcea433295f 100644 --- a/sys/netpfil/ipfilter/netinet/fil.c +++ b/sys/netpfil/ipfilter/netinet/fil.c @@ -437,7 +437,7 @@ static inline void ipf_pr_ipv6hdr(fr_info_t *fin) { ip6_t *ip6 = (ip6_t *)fin->fin_ip; - int p, go = 1, i, hdrcount; + int p, go = 1, i; fr_ip_t *fi = &fin->fin_fi; fin->fin_off = 0; @@ -464,7 +464,6 @@ ipf_pr_ipv6hdr(fr_info_t *fin) if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) fin->fin_flx |= FI_MULTICAST|FI_MBCAST; - hdrcount = 0; while (go && !(fin->fin_flx & FI_SHORT)) { switch (p) { @@ -542,7 +541,6 @@ ipf_pr_ipv6hdr(fr_info_t *fin) go = 0; break; } - hdrcount++; /* * It is important to note that at this point, for the @@ -2590,14 +2588,13 @@ ipf_scanlist(fr_info_t *fin, u_32_t pass) /* functions called from the IPFilter "mainline" in ipf_check(). */ /* ------------------------------------------------------------------------ */ frentry_t * -ipf_acctpkt(fr_info_t *fin, u_32_t *passp) +ipf_acctpkt(fr_info_t *fin, u_32_t *passp __unused) { ipf_main_softc_t *softc = fin->fin_main_soft; char group[FR_GROUPLEN]; frentry_t *fr, *frsave; u_32_t pass, rulen; - passp = passp; fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; if (fr != NULL) { @@ -4200,7 +4197,7 @@ ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) (rev / 10000) % 100, (rev / 100) % 100); #else - rev = rev; + (void)rev; /* UNUSED */ (void) strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version)); #endif @@ -4408,13 +4405,12 @@ frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, OP_ZERO /* zero statistics and counters */ } addrem = OP_ADD; frentry_t frd, *fp, *f, **fprev, **ftail; - void *ptr, *uptr, *cptr; + void *ptr, *uptr; u_int *p, *pp; frgroup_t *fg; char *group; ptr = NULL; - cptr = NULL; fg = NULL; fp = &frd; if (makecopy != 0) { @@ -4532,7 +4528,6 @@ frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, } ptr = NULL; - cptr = NULL; if (FR_ISACCOUNT(fp->fr_flags)) unit = IPL_LOGCOUNT; @@ -7314,11 +7309,10 @@ ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) /* for both IPv4 and IPv6 on the same physical NIC. */ /* ------------------------------------------------------------------------ */ void * -ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) +ipf_resolvenic(ipf_main_softc_t *softc __unused, char *name, int v) { void *nic; - softc = softc; /* gcc -Wextra */ if (name[0] == '\0') return (NULL); @@ -7455,6 +7449,10 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) { ipftoken_t *it, *new; + KMALLOC(new, ipftoken_t *); + if (new != NULL) + bzero((char *)new, sizeof(*new)); + WRITE_ENTER(&softc->ipf_tokens); for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && @@ -7463,10 +7461,6 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) } if (it == NULL) { - KMALLOC(new, ipftoken_t *); - if (new != NULL) - bzero((char *)new, sizeof(*new)); - it = new; new = NULL; if (it == NULL) { @@ -7478,6 +7472,11 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) it->ipt_type = type; it->ipt_ref = 1; } else { + if (new != NULL) { + KFREE(new); + new = NULL; + } + if (it->ipt_complete > 0) it = NULL; else diff --git a/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c b/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c index 04850549db98..6eb6cf2a7a47 100644 --- a/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c +++ b/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c @@ -463,13 +463,14 @@ ipf_send_ip(fr_info_t *fin, mb_t *m) int ipf_send_icmp_err(int type, fr_info_t *fin, int dst) { - int err, hlen, xtra, iclen, ohlen, avail, code; + int err, hlen, xtra, iclen, ohlen, avail; struct in_addr dst4; struct icmp *icmp; struct mbuf *m; i6addr_t dst6; void *ifp; #ifdef USE_INET6 + int code; ip6_t *ip6; #endif ip_t *ip, *ip2; @@ -477,8 +478,8 @@ ipf_send_icmp_err(int type, fr_info_t *fin, int dst) if ((type < 0) || (type >= ICMP_MAXTYPE)) return (-1); - code = fin->fin_icode; #ifdef USE_INET6 + code = fin->fin_icode; /* See NetBSD ip_fil_netbsd.c r1.4: */ if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int))) return (-1); diff --git a/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c index 482e0b456ae5..8c9317c38326 100644 --- a/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c @@ -219,7 +219,7 @@ ipf_p_ftp_soft_destroy(ipf_main_softc_t *softc, void *arg) int -ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { ftpinfo_t *ftp; ftpside_t *f; @@ -228,8 +228,6 @@ ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) if (ftp == NULL) return (-1); - nat = nat; /* LINT */ - aps->aps_data = ftp; aps->aps_psiz = sizeof(ftpinfo_t); aps->aps_sport = htons(fin->fin_sport); @@ -1715,7 +1713,9 @@ ipf_p_ftp_eprt4(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, return (0); if (c != delim) return (0); - addr |= addr; +#if 0 + addr |= (addr << 0); +#endif /* * Get the port number diff --git a/sys/netpfil/ipfilter/netinet/ip_htable.c b/sys/netpfil/ipfilter/netinet/ip_htable.c index 22d427b87a71..91b375f80db1 100644 --- a/sys/netpfil/ipfilter/netinet/ip_htable.c +++ b/sys/netpfil/ipfilter/netinet/ip_htable.c @@ -343,6 +343,7 @@ ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) iph->iph_ref = 1; iph->iph_list = NULL; iph->iph_tail = &iph->iph_list; + iph->iph_unit = unit; iph->iph_next = softh->ipf_htables[unit + 1]; iph->iph_pnext = &softh->ipf_htables[unit + 1]; if (softh->ipf_htables[unit + 1] != NULL) @@ -603,7 +604,7 @@ ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph, switch (iph->iph_type & ~IPHASH_ANON) { case IPHASH_GROUPMAP : - if (ipe->ipe_group != NULL) + if (ipe->ipe_ptr != NULL) ipf_group_del(softc, ipe->ipe_ptr, NULL); break; @@ -973,7 +974,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo) { iphtent_t ipe, *ent; u_int hv; - int bits; bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe)); ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0]; @@ -981,7 +981,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo) ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2]; ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3]; if (ipe.ipe_family == AF_INET) { - bits = count4bits(ipe.ipe_mask.in4_addr); ipe.ipe_addr.i6[1] = 0; ipe.ipe_addr.i6[2] = 0; ipe.ipe_addr.i6[3] = 0; @@ -993,7 +992,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo) } else #ifdef USE_INET6 if (ipe.ipe_family == AF_INET6) { - bits = count6bits(ipe.ipe_mask.i6); hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6, ipe.ipe_mask.i6, iph->iph_size); } else diff --git a/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c b/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c index c6e4be17e22e..d5103c2944dc 100644 --- a/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c @@ -341,15 +341,13 @@ ipf_p_ipsec_inout(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) * UDP/TCP port numbers). */ int -ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { ipsec_pxy_t *ipsec; u_32_t cookies[4]; mb_t *m; int off; - nat = nat; /* LINT */ - if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG)) return (-1); diff --git a/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c b/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c index 026459299efd..aa9e84be19ed 100644 --- a/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c @@ -221,7 +221,7 @@ ipf_p_irc_complete(ircinfo_t *ircp, char *buf, size_t len) int -ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { ircinfo_t *irc; @@ -232,8 +232,6 @@ ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) if (irc == NULL) return (-1); - nat = nat; /* LINT */ - aps->aps_data = irc; aps->aps_psiz = sizeof(ircinfo_t); @@ -422,8 +420,7 @@ ipf_p_irc_send(fr_info_t *fin, nat_t *nat) int -ipf_p_irc_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_irc_out(void *arg, fr_info_t *fin, ap_session_t *aps __unused, nat_t *nat) { - aps = aps; /* LINT */ return (ipf_p_irc_send(fin, nat)); } diff --git a/sys/netpfil/ipfilter/netinet/ip_lookup.c b/sys/netpfil/ipfilter/netinet/ip_lookup.c index b46d1b875003..a52dbef00166 100644 --- a/sys/netpfil/ipfilter/netinet/ip_lookup.c +++ b/sys/netpfil/ipfilter/netinet/ip_lookup.c @@ -230,13 +230,11 @@ ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg) /* ------------------------------------------------------------------------ */ int ipf_lookup_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, - int mode, int uid, void *ctx) + int mode __unused, int uid, void *ctx) { int err; SPL_INT(s); - mode = mode; /* LINT */ - SPL_NET(s); switch (cmd) diff --git a/sys/netpfil/ipfilter/netinet/ip_nat.c b/sys/netpfil/ipfilter/netinet/ip_nat.c index a13c6129a287..972511f43bd5 100644 --- a/sys/netpfil/ipfilter/netinet/ip_nat.c +++ b/sys/netpfil/ipfilter/netinet/ip_nat.c @@ -3224,13 +3224,10 @@ ipf_nat_finalise(fr_info_t *fin, nat_t *nat) ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_32_t sum1, sum2, sumd; frentry_t *fr; - u_32_t flags; #if SOLARIS && defined(_KERNEL) && defined(ICK_M_CTL_MAGIC) qpktinfo_t *qpi = fin->fin_qpi; #endif - flags = nat->nat_flags; - switch (nat->nat_pr[0]) { case IPPROTO_ICMP : @@ -3538,8 +3535,8 @@ ipf_nat_icmperrorlookup(fr_info_t *fin, int dir) { ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; - int flags = 0, type, minlen; - icmphdr_t *icmp, *orgicmp; + int flags = 0, minlen; + icmphdr_t *orgicmp; nat_stat_side_t *nside; tcphdr_t *tcp = NULL; u_short data[2]; @@ -3547,8 +3544,6 @@ ipf_nat_icmperrorlookup(fr_info_t *fin, int dir) ip_t *oip; u_int p; - icmp = fin->fin_dp; - type = icmp->icmp_type; nside = &softn->ipf_nat_stats.ns_side[fin->fin_out]; /* * Does it at least have the return (basic) IP header ? @@ -3999,9 +3994,7 @@ ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p, ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_short sport, dport; - grehdr_t *gre; ipnat_t *ipn; - u_int sflags; nat_t *nat; int nflags; u_32_t dst; @@ -4009,9 +4002,7 @@ ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p, u_int hv, rhv; ifp = fin->fin_ifp; - gre = NULL; dst = mapdst.s_addr; - sflags = flags & NAT_TCPUDPICMP; switch (p) { @@ -4330,14 +4321,12 @@ ipf_nat_outlookup(fr_info_t *fin, u_int flags, u_int p, ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_short sport, dport; - u_int sflags; ipnat_t *ipn; nat_t *nat; void *ifp; u_int hv; ifp = fin->fin_ifp; - sflags = flags & IPN_TCPUDPICMP; switch (p) { @@ -4756,7 +4745,6 @@ ipf_nat_checkout(fr_info_t *fin, u_32_t *passp) struct ifnet *ifp, *sifp; ipf_main_softc_t *softc; ipf_nat_softc_t *softn; - icmphdr_t *icmp = NULL; tcphdr_t *tcp = NULL; int rval, natfailed; u_int nflags = 0; @@ -4802,8 +4790,6 @@ ipf_nat_checkout(fr_info_t *fin, u_32_t *passp) nflags = IPN_UDP; break; case IPPROTO_ICMP : - icmp = fin->fin_dp; - /* * This is an incoming packet, so the destination is * the icmp_id and the source port equals 0 @@ -5463,7 +5449,10 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) { ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; - u_32_t sumd, ipsumd, sum1, sum2; + u_32_t sumd, sum1, sum2; +#if !defined(_KERNEL) || SOLARIS + u_32_t ipsumd; +#endif icmphdr_t *icmp; tcphdr_t *tcp; ipnat_t *np; @@ -5499,7 +5488,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); +#if !defined(_KERNEL) || SOLARIS ipsumd = nat->nat_ipsumd; +#endif /* * Fix up checksums, not by recalculating them, but * simply computing adjustments. @@ -5521,7 +5512,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) sum1 = nat->nat_osrcaddr; sum2 = nat->nat_nsrcaddr; CALC_SUMD(sum1, sum2, sumd); +#if !defined(_KERNEL) || SOLARIS ipsumd -= sumd; +#endif } fin->fin_ip->ip_dst = nat->nat_ndstip; fin->fin_daddr = nat->nat_ndstaddr; @@ -5538,7 +5531,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) sum1 = nat->nat_odstaddr; sum2 = nat->nat_ndstaddr; CALC_SUMD(sum1, sum2, sumd); +#if !defined(_KERNEL) || SOLARIS ipsumd -= sumd; +#endif } fin->fin_ip->ip_dst = nat->nat_osrcip; fin->fin_daddr = nat->nat_osrcaddr; @@ -7352,30 +7347,18 @@ ipf_nat_nextaddr(fr_info_t *fin, nat_addr_t *na, u_32_t *old, u_32_t *dst) { ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; - u_32_t amin, amax, new; + u_32_t new; i6addr_t newip; int error; new = 0; - amin = na->na_addr[0].in4.s_addr; switch (na->na_atype) { case FRI_RANGE : - amax = na->na_addr[1].in4.s_addr; - break; - case FRI_NETMASKED : case FRI_DYNAMIC : case FRI_NORMAL : - /* - * Compute the maximum address by adding the inverse of the - * netmask to the minimum address. - */ - amax = ~na->na_addr[1].in4.s_addr; - amax |= amin; - break; - case FRI_LOOKUP : break; diff --git a/sys/netpfil/ipfilter/netinet/ip_nat6.c b/sys/netpfil/ipfilter/netinet/ip_nat6.c index dbe19c40c2f2..6d5913177b90 100644 --- a/sys/netpfil/ipfilter/netinet/ip_nat6.c +++ b/sys/netpfil/ipfilter/netinet/ip_nat6.c @@ -1130,9 +1130,6 @@ ipf_nat6_finalise(fr_info_t *fin, nat_t *nat) ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_32_t sum1, sum2, sumd; frentry_t *fr; - u_32_t flags; - - flags = nat->nat_flags; switch (fin->fin_p) { @@ -1355,8 +1352,8 @@ ipf_nat6_icmperrorlookup(fr_info_t *fin, int dir) { ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; - struct icmp6_hdr *icmp6, *orgicmp; - int flags = 0, type, minlen; + struct icmp6_hdr *orgicmp; + int flags = 0, minlen; nat_stat_side_t *nside; tcphdr_t *tcp = NULL; u_short data[2]; @@ -1365,8 +1362,6 @@ ipf_nat6_icmperrorlookup(fr_info_t *fin, int dir) u_int p; minlen = 40; - icmp6 = fin->fin_dp; - type = icmp6->icmp6_type; nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out]; /* * Does it at least have the return (basic) IP header ? @@ -1500,9 +1495,8 @@ ipf_nat6_ip6subtract(i6addr_t *ip1, i6addr_t *ip2) i6addr_t l1, l2, d; u_short *s1, *s2, *ds; u_32_t r; - int i, neg; + int i; - neg = 0; l1 = *ip1; l2 = *ip2; s1 = (u_short *)&l1; @@ -1519,7 +1513,6 @@ ipf_nat6_ip6subtract(i6addr_t *ip1, i6addr_t *ip2) } if (s2[0] > s1[0]) { ds[0] = s2[0] + 0x10000 - s1[0]; - neg = 1; } else { ds[0] = s2[0] - s1[0]; } @@ -1869,9 +1862,9 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p, ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_short sport, dport; - grehdr_t *gre; +#ifdef IPF_V6_PROXIES ipnat_t *ipn; - u_int sflags; +#endif nat_t *nat; int nflags; i6addr_t dst; @@ -1881,10 +1874,7 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p, ifp = fin->fin_ifp; sport = 0; dport = 0; - gre = NULL; dst.in6 = *mapdst; - sflags = flags & NAT_TCPUDPICMP; - switch (p) { case IPPROTO_TCP : @@ -1962,8 +1952,8 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p, if ((nat->nat_flags & IPN_TCPUDP) != 0) { - ipn = nat->nat_ptr; #ifdef IPF_V6_PROXIES + ipn = nat->nat_ptr; if ((ipn != NULL) && (nat->nat_aps != NULL)) if (appr_match(fin, nat) != 0) continue; @@ -2192,14 +2182,14 @@ ipf_nat6_outlookup(fr_info_t *fin, u_int flags, u_int p, ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; u_short sport, dport; - u_int sflags; +#ifdef IPF_V6_PROXIES ipnat_t *ipn; +#endif nat_t *nat; void *ifp; u_int hv; ifp = fin->fin_ifp; - sflags = flags & IPN_TCPUDPICMP; sport = 0; dport = 0; @@ -2280,8 +2270,8 @@ ipf_nat6_outlookup(fr_info_t *fin, u_int flags, u_int p, break; } - ipn = nat->nat_ptr; #ifdef IPF_V6_PROXIES + ipn = nat->nat_ptr; if ((ipn != NULL) && (nat->nat_aps != NULL)) if (appr_match(fin, nat) != 0) continue; @@ -2568,7 +2558,6 @@ ipf_nat6_checkout(fr_info_t *fin, u_32_t *passp) ipf_nat_softc_t *softn = softc->ipf_nat_soft; struct icmp6_hdr *icmp6 = NULL; struct ifnet *ifp, *sifp; - tcphdr_t *tcp = NULL; int rval, natfailed; ipnat_t *np = NULL; u_int nflags = 0; @@ -2621,9 +2610,6 @@ ipf_nat6_checkout(fr_info_t *fin, u_32_t *passp) default : break; } - - if ((nflags & IPN_TCPUDP)) - tcp = fin->fin_dp; } ipa = fin->fin_src6; @@ -2965,7 +2951,9 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp) int rval, natfailed; struct ifnet *ifp; i6addr_t ipa, iph; - tcphdr_t *tcp; +#ifdef IPF_V6_PROXIES + tcphdr_t *tcp = NULL; +#endif u_short dport; ipnat_t *np; nat_t *nat; @@ -2973,7 +2961,6 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp) if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0) return (0); - tcp = NULL; icmp6 = NULL; dport = 0; natadd = 1; @@ -3014,7 +3001,9 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp) } if ((nflags & IPN_TCPUDP)) { +#ifdef IPF_V6_PROXIES tcp = fin->fin_dp; +#endif dport = fin->fin_data[1]; } } @@ -3802,32 +3791,19 @@ ipf_nat6_nextaddr(fr_info_t *fin, nat_addr_t *na, i6addr_t *old, i6addr_t *dst) ipf_main_softc_t *softc = fin->fin_main_soft; ipf_nat_softc_t *softn = softc->ipf_nat_soft; i6addr_t newip, new; - u_32_t amin, amax; int error; new.i6[0] = 0; new.i6[1] = 0; new.i6[2] = 0; new.i6[3] = 0; - amin = na->na_addr[0].in4.s_addr; switch (na->na_atype) { case FRI_RANGE : - amax = na->na_addr[1].in4.s_addr; - break; - case FRI_NETMASKED : case FRI_DYNAMIC : case FRI_NORMAL : - /* - * Compute the maximum address by adding the inverse of the - * netmask to the minimum address. - */ - amax = ~na->na_addr[1].in4.s_addr; - amax |= amin; - break; - case FRI_LOOKUP : break; diff --git a/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c b/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c index 2ad642adfbcd..f9c1ab50b8a2 100644 --- a/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c @@ -67,7 +67,7 @@ ipf_p_netbios_main_unload(void) int -ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps __unused, nat_t *nat __unused) { char dgmbuf[6]; int off, dlen; @@ -75,9 +75,6 @@ ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) ip_t *ip; mb_t *m; - aps = aps; /* LINT */ - nat = nat; /* LINT */ - m = fin->fin_m; dlen = fin->fin_dlen - sizeof(*udp); /* diff --git a/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c index 0ac19b067d2d..dc4c67dc14f0 100644 --- a/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c @@ -281,7 +281,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev) tcphdr_t *tcp; int dlen, off; u_short len; - char *msg; tcp = fin->fin_dp; dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); @@ -310,8 +309,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev) return (-1); } - msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); - while (dlen > 0) { off += pptps->pptps_bytes; if (pptps->pptps_gothdr == 0) { @@ -337,7 +334,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev) } } dlen -= len; - msg += len; off += len; pptps->pptps_gothdr = 1; @@ -381,7 +377,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev) pptps->pptps_len = 0; start += len; - msg += len; dlen -= len; } diff --git a/sys/netpfil/ipfilter/netinet/ip_proxy.c b/sys/netpfil/ipfilter/netinet/ip_proxy.c index 9785fc37d3da..9fb6dbd2a9e1 100644 --- a/sys/netpfil/ipfilter/netinet/ip_proxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_proxy.c @@ -679,14 +679,12 @@ ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *np) /* ------------------------------------------------------------------------ */ int ipf_proxy_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, - int mode, void *ctx) + int mode __unused, void *ctx) { ap_ctl_t ctl; caddr_t ptr; int error; - mode = mode; /* LINT */ - switch (cmd) { case SIOCPROXY : diff --git a/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c b/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c index 2cfaaa58200f..94f0e3ada707 100644 --- a/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c @@ -49,12 +49,10 @@ ipf_p_raudio_main_unload(void) * Setup for a new proxy to handle Real Audio. */ int -ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { raudio_t *rap; - nat = nat; /* LINT */ - if (fin->fin_v != 4) return (-1); @@ -72,7 +70,7 @@ ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) int -ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { raudio_t *rap = aps->aps_data; unsigned char membuf[512 + 1], *s; @@ -82,8 +80,6 @@ ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) int len = 0; mb_t *m; - nat = nat; /* LINT */ - /* * If we've already processed the start messages, then nothing left * for the proxy to do. diff --git a/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c b/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c index 778f14f442de..b85794e75499 100644 --- a/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c @@ -63,18 +63,12 @@ ipf_p_rcmd_main_unload(void) * Setup for a new RCMD proxy. */ int -ipf_p_rcmd_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_rcmd_new(void *arg, fr_info_t *fin __unused, ap_session_t *aps, nat_t *nat) { tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; rcmdinfo_t *rc; ipnat_t *ipn; - ipnat_t *np; - int size; - fin = fin; /* LINT */ - - np = nat->nat_ptr; - size = np->in_size; KMALLOC(rc, rcmdinfo_t *); if (rc == NULL) { #ifdef IP_RCMD_PROXY_DEBUG diff --git a/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c b/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c index f8f4d2d325e1..c608f84d7b3b 100644 --- a/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c @@ -144,12 +144,10 @@ ipf_p_rpcb_main_unload(void) /* Allocate resources for per-session proxy structures. */ /* -------------------------------------------------------------------- */ int -ipf_p_rpcb_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_rpcb_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused) { rpcb_session_t *rs; - nat = nat; /* LINT */ - if (fin->fin_v != 4) return (-1); @@ -1023,10 +1021,8 @@ ipf_p_rpcb_lookup(rpcb_session_t *rs, u_32_t xid) /* Free the RPCB transaction record rx from the chain of entries. */ /* -------------------------------------------------------------------- */ static void -ipf_p_rpcb_deref(rpcb_session_t *rs, rpcb_xact_t *rx) +ipf_p_rpcb_deref(rpcb_session_t *rs __unused, rpcb_xact_t *rx) { - rs = rs; /* LINT */ - if (rx == NULL) return; diff --git a/sys/netpfil/ipfilter/netinet/ip_state.c b/sys/netpfil/ipfilter/netinet/ip_state.c index 8fe11e3f1215..36fdf23cd062 100644 --- a/sys/netpfil/ipfilter/netinet/ip_state.c +++ b/sys/netpfil/ipfilter/netinet/ip_state.c @@ -883,7 +883,7 @@ ipf_state_putent(ipf_main_softc_t *softc, ipf_state_softc_t *softs, { ipstate_t *is, *isn; ipstate_save_t ips; - int error, out, i; + int error, i; frentry_t *fr; char *name; @@ -929,7 +929,6 @@ ipf_state_putent(ipf_main_softc_t *softc, ipf_state_softc_t *softs, return (ENOMEM); } bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); - out = fr->fr_flags & FR_OUTQUE ? 1 : 0; isn->is_rule = fr; ips.ips_is.is_rule = fr; MUTEX_NUKE(&fr->fr_lock); @@ -2207,20 +2206,6 @@ ipf_state_tcpinwindow(fr_info_t *fin, tcpdata_t *fdata, tcpdata_t *tdata, (ackskew >= -1) && (ackskew <= 1)) { inseq = 1; } else if (!(flags & IS_TCPFSM)) { - int i; - - i = (fin->fin_rev << 1) + fin->fin_out; - -#if 0 - if (is_pkts[i]0 == 0) { - /* - * Picking up a connection in the middle, the "next" - * packet seen from a direction that is new should be - * accepted, even if it appears out of sequence. - */ - inseq = 1; - } else -#endif if (!(fdata->td_winflags & (TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) { /* @@ -2616,7 +2601,7 @@ ipf_checkicmpmatchingstate(fr_info_t *fin) icmphdr_t *icmp; fr_info_t ofin; tcphdr_t *tcp; - int type, len; + int len; u_char pr; ip_t *oip; u_int hv; @@ -2634,7 +2619,6 @@ ipf_checkicmpmatchingstate(fr_info_t *fin) return (NULL); } ic = fin->fin_dp; - type = ic->icmp_type; oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); /* @@ -4362,7 +4346,6 @@ ipf_checkicmp6matchingstate(fr_info_t *fin) ip6_t *oip6; u_char pr; u_int hv; - int type; /* * Does it at least have the return (basic) IP header ? @@ -4377,7 +4360,6 @@ ipf_checkicmp6matchingstate(fr_info_t *fin) } ic6 = fin->fin_dp; - type = ic6->icmp6_type; oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN); if (fin->fin_plen < sizeof(*oip6)) { diff --git a/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c index d81de100120b..3c737b38aacc 100644 --- a/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c +++ b/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c @@ -151,7 +151,7 @@ ipf_p_tftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) int -ipf_p_tftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) +ipf_p_tftp_new(void *arg, fr_info_t *fin __unused, ap_session_t *aps, nat_t *nat) { udphdr_t *udp; tftpinfo_t *ti; @@ -159,8 +159,6 @@ ipf_p_tftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) ipnat_t *np; int size; - fin = fin; /* LINT */ - np = nat->nat_ptr; size = np->in_size; diff --git a/sys/netpfil/ipfilter/netinet/ipf_rb.h b/sys/netpfil/ipfilter/netinet/ipf_rb.h index e047c7f44a4a..334311502aab 100644 --- a/sys/netpfil/ipfilter/netinet/ipf_rb.h +++ b/sys/netpfil/ipfilter/netinet/ipf_rb.h @@ -305,13 +305,11 @@ _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\ _t *prev; \ _t *next; \ _t *node = head->top._f.right; \ - _t *base; \ \ while (node != &_n##_rb_zero) \ node = node->_f.left; \ \ for (;;) { \ - base = node; \ prev = node; \ while ((node->_f.parent->_f.right == node) && \ (node != &_n##_rb_zero)) { \ diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c index 6a87ea2471cb..cb96d2fcc44c 100644 --- a/sys/netpfil/pf/if_pflog.c +++ b/sys/netpfil/pf/if_pflog.c @@ -284,12 +284,12 @@ pflog_packet(uint8_t action, u_int8_t reason, * state lock, since this leads to unsafe LOR. * These conditions are very very rare, however. */ - if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe) + if (trigger->log & PF_LOG_USER && !pd->lookup.done && lookupsafe) pd->lookup.done = pf_socket_lookup(pd); - if (pd->lookup.done > 0) + if (trigger->log & PF_LOG_USER && pd->lookup.done > 0) hdr.uid = pd->lookup.uid; else - hdr.uid = UID_MAX; + hdr.uid = -1; hdr.pid = NO_PID; hdr.rule_uid = rm->cuid; hdr.rule_pid = rm->cpid; diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index fdedb9424117..4e03584b8f85 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -532,6 +532,7 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) struct pf_kpooladdr *rpool_first; int error; uint8_t rt = 0; + int n = 0; PF_RULES_RASSERT(); @@ -557,10 +558,12 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) */ if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) && (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->pfs_1301.rule) < - pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) - r = pf_main_ruleset.rules[ - PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)]; - else + pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) { + TAILQ_FOREACH(r, pf_main_ruleset.rules[ + PF_RULESET_FILTER].active.ptr, entries) + if (ntohl(sp->pfs_1301.rule) == n++) + break; + } else r = &V_pf_default_rule; /* @@ -763,6 +766,10 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) __func__, msg_version); } + if (! (st->act.rtableid == -1 || + (st->act.rtableid >= 0 && st->act.rtableid < rt_numfibs))) + goto cleanup; + st->id = sp->pfs_1301.id; st->creatorid = sp->pfs_1301.creatorid; pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src); @@ -1083,7 +1090,7 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action) msg_version = PFSYNC_MSG_VERSION_1400; break; default: - V_pfsyncstats.pfsyncs_badact++; + V_pfsyncstats.pfsyncs_badver++; return (-1); } @@ -1110,9 +1117,8 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action) continue; } - if (pfsync_state_import(sp, flags, msg_version) == ENOMEM) - /* Drop out, but process the rest of the actions. */ - break; + if (pfsync_state_import(sp, flags, msg_version) != 0) + V_pfsyncstats.pfsyncs_badact++; } return (total_len); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 127b29320acb..009f7e4d78b1 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -4579,7 +4579,7 @@ pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p) static int pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u) { - if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE) + if (u == -1 && op != PF_OP_EQ && op != PF_OP_NE) return (0); return (pf_match(op, a1, a2, u)); } @@ -4587,7 +4587,7 @@ pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u) static int pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) { - if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE) + if (g == -1 && op != PF_OP_EQ && op != PF_OP_NE) return (0); return (pf_match(op, a1, a2, g)); } @@ -4914,8 +4914,8 @@ pf_socket_lookup(struct pf_pdesc *pd) struct inpcbinfo *pi; struct inpcb *inp; - pd->lookup.uid = UID_MAX; - pd->lookup.gid = GID_MAX; + pd->lookup.uid = -1; + pd->lookup.gid = -1; switch (pd->proto) { case IPPROTO_TCP: @@ -5901,18 +5901,17 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, M_SETFIB(pd->m, pd->act.rtableid); if (r->rt) { - struct pf_ksrc_node *sn = NULL; - struct pf_srchash *snh = NULL; /* * Set act.rt here instead of in pf_rule_to_actions() because * it is applied only from the last pass rule. */ pd->act.rt = r->rt; - /* Don't use REASON_SET, pf_map_addr increases the reason counters */ - ctx.reason = pf_map_addr_sn(pd->af, r, pd->src, &pd->act.rt_addr, - &pd->act.rt_kif, NULL, &sn, &snh, &(r->route), PF_SN_ROUTE); - if (ctx.reason != 0) + if ((transerror = pf_map_addr_sn(pd->af, r, pd->src, + &pd->act.rt_addr, &pd->act.rt_kif, NULL, &(r->route), + PF_SN_ROUTE)) != PFRES_MATCH) { + REASON_SET(&ctx.reason, transerror); goto cleanup; + } } if (pd->virtual_proto != PF_VPROTO_FRAGMENT && @@ -6056,9 +6055,16 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx, /* src node for translation rule */ if (ctx->nr != NULL) { KASSERT(ctx->nat_pool != NULL, ("%s: nat_pool is NULL", __func__)); + /* + * The NAT addresses are chosen during ruleset parsing. + * The new afto code stores post-nat addresses in nsaddr. + * The old nat code (also used for new nat-to rules) creates + * state keys and stores addresses in them. + */ if ((ctx->nat_pool->opts & PF_POOL_STICKYADDR) && (sn_reason = pf_insert_src_node(sns, snhs, ctx->nr, - &ctx->sk->addr[pd->sidx], pd->af, &ctx->nk->addr[1], NULL, + ctx->sk ? &(ctx->sk->addr[pd->sidx]) : pd->src, pd->af, + ctx->nk ? &(ctx->nk->addr[1]) : &(pd->nsaddr), NULL, PF_SN_NAT)) != 0 ) { REASON_SET(&ctx->reason, sn_reason); goto csfailed; @@ -6213,7 +6219,7 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx, if (ctx->tag > 0) s->tag = ctx->tag; if (pd->proto == IPPROTO_TCP && (tcp_get_flags(th) & (TH_SYN|TH_ACK)) == - TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { + TH_SYN && r->keep_state == PF_STATE_SYNPROXY && pd->dir == PF_IN) { pf_set_protostate(s, PF_PEER_SRC, PF_TCPS_PROXY_SRC); pf_undo_nat(ctx->nr, pd, bip_sum); s->src.seqhi = arc4random(); @@ -9062,6 +9068,9 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, goto bad; } + if (r->rt == PF_DUPTO) + skip_test = true; + if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS) { @@ -9364,6 +9373,9 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, goto bad; } + if (r->rt == PF_DUPTO) + skip_test = true; + if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, ifp, &m0, inp, &pd->act) != PF_PASS) { @@ -10052,6 +10064,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, pd->didx = (dir == PF_IN) ? 1 : 0; pd->af = pd->naf = af; + PF_RULES_ASSERT(); + TAILQ_INIT(&pd->sctp_multihome_jobs); if (default_actions != NULL) memcpy(&pd->act, default_actions, sizeof(pd->act)); @@ -10127,6 +10141,12 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, } h = mtod(pd->m, struct ip6_hdr *); + if (pd->m->m_pkthdr.len < + sizeof(struct ip6_hdr) + ntohs(h->ip6_plen)) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } if (pf_walk_header6(pd, h, reason) != PF_PASS) { *action = PF_DROP; @@ -10465,35 +10485,30 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0 PF_RULES_RLOCK_TRACKER; KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir)); M_ASSERTPKTHDR(*m0); + NET_EPOCH_ASSERT(); if (!V_pf_status.running) return (PF_PASS); - PF_RULES_RLOCK(); - kif = (struct pfi_kkif *)ifp->if_pf_kif; if (__predict_false(kif == NULL)) { DPFPRINTF(PF_DEBUG_URGENT, ("%s: kif == NULL, if_xname %s\n", __func__, ifp->if_xname)); - PF_RULES_RUNLOCK(); return (PF_DROP); } if (kif->pfik_flags & PFI_IFLAG_SKIP) { - PF_RULES_RUNLOCK(); return (PF_PASS); } if ((*m0)->m_flags & M_SKIP_FIREWALL) { - PF_RULES_RUNLOCK(); return (PF_PASS); } if (__predict_false(! M_WRITABLE(*m0))) { *m0 = m_unshare(*m0, M_NOWAIT); if (*m0 == NULL) { - PF_RULES_RUNLOCK(); return (PF_DROP); } } @@ -10506,12 +10521,10 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0 ifp = ifnet_byindexgen(pd.pf_mtag->if_index, pd.pf_mtag->if_idxgen); if (ifp == NULL || ifp->if_flags & IFF_DYING) { - PF_RULES_RUNLOCK(); m_freem(*m0); *m0 = NULL; return (PF_PASS); } - PF_RULES_RUNLOCK(); (ifp->if_output)(ifp, *m0, sintosa(&pd.pf_mtag->dst), NULL); *m0 = NULL; return (PF_PASS); @@ -10526,11 +10539,12 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0 /* But only once. We may see the packet multiple times (e.g. * PFIL_IN/PFIL_OUT). */ pf_dummynet_flag_remove(pd.m, pd.pf_mtag); - PF_RULES_RUNLOCK(); return (PF_PASS); } + PF_RULES_RLOCK(); + if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason, kif, default_actions) == -1) { if (action != PF_PASS) diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h index 2009d2907985..cfff58064922 100644 --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -140,7 +140,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, #define PF_LOG 0x01 #define PF_LOG_ALL 0x02 -#define PF_LOG_SOCKET_LOOKUP 0x04 +#define PF_LOG_USER 0x04 #define PF_LOG_FORCE 0x08 #define PF_LOG_MATCHES 0x10 @@ -490,6 +490,7 @@ struct pf_osfp_ioctl { #define PF_ANCHOR_NAME_SIZE 64 #define PF_ANCHOR_MAXPATH (MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1) +#define PF_OPTIMIZER_TABLE_PFX "__automatic_" struct pf_rule { struct pf_rule_addr src; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 357b2be194a5..3caa0d2e3b11 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -1274,7 +1274,9 @@ pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) PF_MD5_UPD(pfr, addr.iflags); break; case PF_ADDR_TABLE: - PF_MD5_UPD(pfr, addr.v.tblname); + if (strncmp(pfr->addr.v.tblname, PF_OPTIMIZER_TABLE_PFX, + strlen(PF_OPTIMIZER_TABLE_PFX))) + PF_MD5_UPD(pfr, addr.v.tblname); break; case PF_ADDR_ADDRMASK: /* XXX ignore af? */ @@ -1357,7 +1359,7 @@ static int pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) { struct pf_kruleset *rs; - struct pf_krule *rule, **old_array, *old_rule; + struct pf_krule *rule, *old_rule; struct pf_krulequeue *old_rules; struct pf_krule_global *old_tree; int error; @@ -1382,13 +1384,10 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) /* Swap rules, keep the old. */ old_rules = rs->rules[rs_num].active.ptr; old_rcount = rs->rules[rs_num].active.rcount; - old_array = rs->rules[rs_num].active.ptr_array; old_tree = rs->rules[rs_num].active.tree; rs->rules[rs_num].active.ptr = rs->rules[rs_num].inactive.ptr; - rs->rules[rs_num].active.ptr_array = - rs->rules[rs_num].inactive.ptr_array; rs->rules[rs_num].active.tree = rs->rules[rs_num].inactive.tree; rs->rules[rs_num].active.rcount = @@ -1418,7 +1417,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) } rs->rules[rs_num].inactive.ptr = old_rules; - rs->rules[rs_num].inactive.ptr_array = old_array; rs->rules[rs_num].inactive.tree = NULL; /* important for pf_ioctl_addrule */ rs->rules[rs_num].inactive.rcount = old_rcount; @@ -1431,9 +1429,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) while ((rule = TAILQ_FIRST(old_rules)) != NULL) pf_unlink_rule_locked(old_rules, rule); PF_UNLNKDRULES_UNLOCK(); - if (rs->rules[rs_num].inactive.ptr_array) - free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); - rs->rules[rs_num].inactive.ptr_array = NULL; rs->rules[rs_num].inactive.rcount = 0; rs->rules[rs_num].inactive.open = 0; pf_remove_if_empty_kruleset(rs); @@ -1456,24 +1451,11 @@ pf_setup_pfsync_matching(struct pf_kruleset *rs) if (rs_cnt == PF_RULESET_SCRUB) continue; - if (rs->rules[rs_cnt].inactive.ptr_array) - free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); - rs->rules[rs_cnt].inactive.ptr_array = NULL; - if (rs->rules[rs_cnt].inactive.rcount) { - rs->rules[rs_cnt].inactive.ptr_array = - mallocarray(rs->rules[rs_cnt].inactive.rcount, - sizeof(struct pf_rule **), - M_TEMP, M_NOWAIT); - - if (!rs->rules[rs_cnt].inactive.ptr_array) - return (ENOMEM); - } - - TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, - entries) { - pf_hash_rule_rolling(&ctx, rule); - (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; + TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, + entries) { + pf_hash_rule_rolling(&ctx, rule); + } } } @@ -2059,6 +2041,19 @@ pf_ioctl_getrules(struct pfioc_rule *pr) return (0); } +static int +pf_validate_range(uint8_t op, uint16_t port[2]) +{ + uint16_t a = ntohs(port[0]); + uint16_t b = ntohs(port[1]); + + if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */ + (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */ + (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */ + return 1; + return 0; +} + int pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, uint32_t pool_ticket, const char *anchor, const char *anchor_call, @@ -2078,6 +2073,11 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, #define ERROUT(x) ERROUT_FUNCTION(errout, x) + if (pf_validate_range(rule->src.port_op, rule->src.port)) + ERROUT(EINVAL); + if (pf_validate_range(rule->dst.port_op, rule->dst.port)) + ERROUT(EINVAL); + if (rule->ifname[0]) kif = pf_kkif_create(M_WAITOK); if (rule->rcv_ifname[0]) @@ -2155,51 +2155,51 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, rule->rcv_kif = NULL; if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs) - error = EBUSY; + ERROUT(EBUSY); #ifdef ALTQ /* set queue IDs */ if (rule->qname[0] != 0) { if ((rule->qid = pf_qname2qid(rule->qname)) == 0) - error = EBUSY; + ERROUT(EBUSY); else if (rule->pqname[0] != 0) { if ((rule->pqid = pf_qname2qid(rule->pqname)) == 0) - error = EBUSY; + ERROUT(EBUSY); } else rule->pqid = rule->qid; } #endif if (rule->tagname[0]) if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) - error = EBUSY; + ERROUT(EBUSY); if (rule->match_tagname[0]) if ((rule->match_tag = pf_tagname2tag(rule->match_tagname)) == 0) - error = EBUSY; + ERROUT(EBUSY); if (rule->rt && !rule->direction) - error = EINVAL; + ERROUT(EINVAL); if (!rule->log) rule->logif = 0; if (! pf_init_threshold(&rule->pktrate, rule->pktrate.limit, rule->pktrate.seconds)) - error = ENOMEM; + ERROUT(ENOMEM); if (pf_addr_setup(ruleset, &rule->src.addr, rule->af)) - error = ENOMEM; + ERROUT(ENOMEM); if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af)) - error = ENOMEM; + ERROUT(ENOMEM); if (pf_kanchor_setup(rule, ruleset, anchor_call)) - error = EINVAL; + ERROUT(EINVAL); if (rule->scrub_flags & PFSTATE_SETPRIO && (rule->set_prio[0] > PF_PRIO_MAX || rule->set_prio[1] > PF_PRIO_MAX)) - error = EINVAL; + ERROUT(EINVAL); for (int i = 0; i < 3; i++) { TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries) if (pa->addr.type == PF_ADDR_TABLE) { pa->addr.p.tbl = pfr_attach_table(ruleset, pa->addr.v.tblname); if (pa->addr.p.tbl == NULL) - error = ENOMEM; + ERROUT(ENOMEM); } } @@ -2207,7 +2207,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, if (rule->overload_tblname[0]) { if ((rule->overload_tbl = pfr_attach_table(ruleset, rule->overload_tblname)) == NULL) - error = EINVAL; + ERROUT(EINVAL); else rule->overload_tbl->pfrkt_flags |= PFR_TFLAG_ACTIVE; @@ -2230,23 +2230,19 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, if (((rule->action == PF_NAT) || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) && rule->anchor == NULL && TAILQ_FIRST(&rule->rdr.list) == NULL) { - error = EINVAL; + ERROUT(EINVAL); } if (rule->rt > PF_NOPFROUTE && (TAILQ_FIRST(&rule->route.list) == NULL)) { - error = EINVAL; + ERROUT(EINVAL); } if (rule->action == PF_PASS && (rule->rdr.opts & PF_POOL_STICKYADDR || rule->nat.opts & PF_POOL_STICKYADDR) && !rule->keep_state) { - error = EINVAL; + ERROUT(EINVAL); } - if (error) { - pf_free_rule(rule); - rule = NULL; - ERROUT(error); - } + MPASS(error == 0); rule->nat.cur = TAILQ_FIRST(&rule->nat.list); rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list); @@ -2699,7 +2695,7 @@ pf_ioctl_get_addr(struct pf_nl_pooladdr *pp) PF_RULES_RLOCK_TRACKER; - pp->anchor[sizeof(pp->anchor) - 1] = 0; + pp->anchor[sizeof(pp->anchor) - 1] = '\0'; PF_RULES_RLOCK(); pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action, @@ -2732,7 +2728,7 @@ pf_ioctl_get_rulesets(struct pfioc_ruleset *pr) PF_RULES_RLOCK_TRACKER; - pr->path[sizeof(pr->path) - 1] = 0; + pr->path[sizeof(pr->path) - 1] = '\0'; PF_RULES_RLOCK(); if ((ruleset = pf_find_kruleset(pr->path)) == NULL) { @@ -2771,7 +2767,7 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr) return (ENOENT); } - pr->name[0] = 0; + pr->name[0] = '\0'; if (ruleset == &pf_main_ruleset) { /* XXX kludge for pf_main_ruleset */ RB_FOREACH(anchor, pf_kanchor_global, &V_pf_anchors) @@ -2796,6 +2792,78 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr) return (error); } +int +pf_ioctl_natlook(struct pfioc_natlook *pnl) +{ + struct pf_state_key *sk; + struct pf_kstate *state; + struct pf_state_key_cmp key; + int m = 0, direction = pnl->direction; + int sidx, didx; + + /* NATLOOK src and dst are reversed, so reverse sidx/didx */ + sidx = (direction == PF_IN) ? 1 : 0; + didx = (direction == PF_IN) ? 0 : 1; + + if (!pnl->proto || + PF_AZERO(&pnl->saddr, pnl->af) || + PF_AZERO(&pnl->daddr, pnl->af) || + ((pnl->proto == IPPROTO_TCP || + pnl->proto == IPPROTO_UDP) && + (!pnl->dport || !pnl->sport))) + return (EINVAL); + + switch (pnl->direction) { + case PF_IN: + case PF_OUT: + case PF_INOUT: + break; + default: + return (EINVAL); + } + + switch (pnl->af) { +#ifdef INET + case AF_INET: + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + break; +#endif /* INET6 */ + default: + return (EAFNOSUPPORT); + } + + bzero(&key, sizeof(key)); + key.af = pnl->af; + key.proto = pnl->proto; + pf_addrcpy(&key.addr[sidx], &pnl->saddr, pnl->af); + key.port[sidx] = pnl->sport; + pf_addrcpy(&key.addr[didx], &pnl->daddr, pnl->af); + key.port[didx] = pnl->dport; + + state = pf_find_state_all(&key, direction, &m); + if (state == NULL) + return (ENOENT); + + if (m > 1) { + PF_STATE_UNLOCK(state); + return (E2BIG); /* more than one state */ + } + + sk = state->key[sidx]; + pf_addrcpy(&pnl->rsaddr, + &sk->addr[sidx], sk->af); + pnl->rsport = sk->port[sidx]; + pf_addrcpy(&pnl->rdaddr, + &sk->addr[didx], sk->af); + pnl->rdport = sk->port[didx]; + PF_STATE_UNLOCK(state); + + return (0); +} + static int pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { @@ -3502,7 +3570,7 @@ DIOCADDRULENV_error: break; } - pr->anchor[sizeof(pr->anchor) - 1] = 0; + pr->anchor[sizeof(pr->anchor) - 1] = '\0'; /* Frees rule on error */ error = pf_ioctl_addrule(rule, pr->ticket, pr->pool_ticket, @@ -3514,7 +3582,7 @@ DIOCADDRULENV_error: case DIOCGETRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; - pr->anchor[sizeof(pr->anchor) - 1] = 0; + pr->anchor[sizeof(pr->anchor) - 1] = '\0'; error = pf_ioctl_getrules(pr); @@ -3653,7 +3721,7 @@ DIOCGETRULENV_error: u_int32_t nr = 0; int rs_num; - pcr->anchor[sizeof(pcr->anchor) - 1] = 0; + pcr->anchor[sizeof(pcr->anchor) - 1] = '\0'; if (pcr->action < PF_CHANGE_ADD_HEAD || pcr->action > PF_CHANGE_GET_TICKET) { @@ -4133,51 +4201,8 @@ DIOCGETSTATESV2_full: case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; - struct pf_state_key *sk; - struct pf_kstate *state; - struct pf_state_key_cmp key; - int m = 0, direction = pnl->direction; - int sidx, didx; - - /* NATLOOK src and dst are reversed, so reverse sidx/didx */ - sidx = (direction == PF_IN) ? 1 : 0; - didx = (direction == PF_IN) ? 0 : 1; - - if (!pnl->proto || - PF_AZERO(&pnl->saddr, pnl->af) || - PF_AZERO(&pnl->daddr, pnl->af) || - ((pnl->proto == IPPROTO_TCP || - pnl->proto == IPPROTO_UDP) && - (!pnl->dport || !pnl->sport))) - error = EINVAL; - else { - bzero(&key, sizeof(key)); - key.af = pnl->af; - key.proto = pnl->proto; - pf_addrcpy(&key.addr[sidx], &pnl->saddr, pnl->af); - key.port[sidx] = pnl->sport; - pf_addrcpy(&key.addr[didx], &pnl->daddr, pnl->af); - key.port[didx] = pnl->dport; - - state = pf_find_state_all(&key, direction, &m); - if (state == NULL) { - error = ENOENT; - } else { - if (m > 1) { - PF_STATE_UNLOCK(state); - error = E2BIG; /* more than one state */ - } else { - sk = state->key[sidx]; - pf_addrcpy(&pnl->rsaddr, - &sk->addr[sidx], sk->af); - pnl->rsport = sk->port[sidx]; - pf_addrcpy(&pnl->rdaddr, - &sk->addr[didx], sk->af); - pnl->rdport = sk->port[didx]; - PF_STATE_UNLOCK(state); - } - } - } + + error = pf_ioctl_natlook(pnl); break; } @@ -4498,7 +4523,7 @@ DIOCGETSTATESV2_full: struct pf_kruleset *ruleset; struct pfi_kkif *kif = NULL; - pca->anchor[sizeof(pca->anchor) - 1] = 0; + pca->anchor[sizeof(pca->anchor) - 1] = '\0'; if (pca->action < PF_CHANGE_ADD_HEAD || pca->action > PF_CHANGE_REMOVE) { @@ -4629,7 +4654,7 @@ DIOCCHANGEADDR_error: case DIOCGETRULESETS: { struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; - pr->path[sizeof(pr->path) - 1] = 0; + pr->path[sizeof(pr->path) - 1] = '\0'; error = pf_ioctl_get_rulesets(pr); break; @@ -4638,7 +4663,7 @@ DIOCCHANGEADDR_error: case DIOCGETRULESET: { struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; - pr->path[sizeof(pr->path) - 1] = 0; + pr->path[sizeof(pr->path) - 1] = '\0'; error = pf_ioctl_get_ruleset(pr); break; @@ -5362,7 +5387,7 @@ DIOCCHANGEADDR_error: PF_RULES_WLOCK(); /* First makes sure everything will succeed. */ for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { - ioe->anchor[sizeof(ioe->anchor) - 1] = 0; + ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; switch (ioe->rs_num) { case PF_RULESET_ETH: ers = pf_find_keth_ruleset(ioe->anchor); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 308d76c46e5b..26f7ab41eef4 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -80,7 +80,6 @@ static enum pf_test_status pf_step_into_translation_anchor(int, struct pf_test_c struct pf_krule *); static int pf_get_sport(struct pf_pdesc *, struct pf_krule *, struct pf_addr *, uint16_t *, uint16_t, uint16_t, - struct pf_ksrc_node **, struct pf_srchash **, struct pf_kpool *, struct pf_udp_mapping **, pf_sn_types_t); static bool pf_islinklocal(const sa_family_t, const struct pf_addr *); @@ -291,10 +290,8 @@ pf_match_translation(int rs_num, struct pf_test_ctx *ctx) } static int -pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, - struct pf_addr *naddr, uint16_t *nport, uint16_t low, - uint16_t high, struct pf_ksrc_node **sn, - struct pf_srchash **sh, struct pf_kpool *rpool, +pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, struct pf_addr *naddr, + uint16_t *nport, uint16_t low, uint16_t high, struct pf_kpool *rpool, struct pf_udp_mapping **udp_mapping, pf_sn_types_t sn_type) { struct pf_state_key_cmp key; @@ -322,19 +319,24 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, pf_addrcpy(&udp_source.addr, &pd->nsaddr, pd->af); udp_source.port = pd->nsport; if (udp_mapping) { + struct pf_ksrc_node *sn = NULL; + struct pf_srchash *sh = NULL; *udp_mapping = pf_udp_mapping_find(&udp_source); if (*udp_mapping) { pf_addrcpy(naddr, &(*udp_mapping)->endpoints[1].addr, pd->af); *nport = (*udp_mapping)->endpoints[1].port; - /* Try to find a src_node as per pf_map_addr(). */ - if (*sn == NULL && rpool->opts & PF_POOL_STICKYADDR && + /* + * Try to find a src_node as per pf_map_addr(). + * XXX: Why? This code seems to do nothing. + */ + if (rpool->opts & PF_POOL_STICKYADDR && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) - *sn = pf_find_src_node(&pd->nsaddr, r, - pd->af, sh, sn_type, false); - if (*sn != NULL) - PF_SRC_NODE_UNLOCK(*sn); + sn = pf_find_src_node(&pd->nsaddr, r, + pd->af, &sh, sn_type, false); + if (sn != NULL) + PF_SRC_NODE_UNLOCK(sn); return (0); } else { *udp_mapping = pf_udp_mapping_create(pd->af, &pd->nsaddr, @@ -346,7 +348,7 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, } if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL, &init_addr, - sn, sh, rpool, sn_type)) + rpool, sn_type)) goto failed; if (pd->proto == IPPROTO_ICMP) { @@ -470,9 +472,8 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, * pick a different source address since we're out * of free port choices for the current one. */ - (*sn) = NULL; if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL, - &init_addr, sn, sh, rpool, sn_type)) + &init_addr, rpool, sn_type)) return (1); break; case PF_POOL_NONE: @@ -503,7 +504,6 @@ pf_islinklocal(const sa_family_t af, const struct pf_addr *addr) static int pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, struct pf_addr *naddr, uint16_t *nport, - struct pf_ksrc_node **sn, struct pf_srchash **sh, struct pf_udp_mapping **udp_mapping, struct pf_kpool *rpool) { uint16_t psmask, low, highmask; @@ -523,16 +523,14 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, for (i = cut; i <= ahigh; i++) { low = (i << ashift) | psmask; - if (!pf_get_sport(pd, r, - naddr, nport, low, low | highmask, sn, sh, rpool, - udp_mapping, PF_SN_NAT)) + if (!pf_get_sport(pd, r, naddr, nport, low, low | highmask, + rpool, udp_mapping, PF_SN_NAT)) return (0); } for (i = cut - 1; i > 0; i--) { low = (i << ashift) | psmask; - if (!pf_get_sport(pd, r, - naddr, nport, low, low | highmask, sn, sh, rpool, - udp_mapping, PF_SN_NAT)) + if (!pf_get_sport(pd, r, naddr, nport, low, low | highmask, + rpool, udp_mapping, PF_SN_NAT)) return (0); } return (1); @@ -545,6 +543,7 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, { u_short reason = PFRES_MATCH; struct pf_addr *raddr = NULL, *rmask = NULL; + struct pfr_ktable *kt; uint64_t hashidx; int cnt; @@ -600,29 +599,25 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, pf_poolmask(naddr, raddr, rmask, saddr, af); break; case PF_POOL_RANDOM: - if (rpool->cur->addr.type == PF_ADDR_TABLE) { - cnt = rpool->cur->addr.p.tbl->pfrkt_cnt; - if (cnt == 0) - rpool->tblidx = 0; + if (rpool->cur->addr.type == PF_ADDR_TABLE || + rpool->cur->addr.type == PF_ADDR_DYNIFTL) { + if (rpool->cur->addr.type == PF_ADDR_TABLE) + kt = rpool->cur->addr.p.tbl; else - rpool->tblidx = (int)arc4random_uniform(cnt); - memset(&rpool->counter, 0, sizeof(rpool->counter)); - if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af, NULL)) { + kt = rpool->cur->addr.p.dyn->pfid_kt; + kt = pfr_ktable_select_active(kt); + if (kt == NULL) { reason = PFRES_MAPFAILED; goto done_pool_mtx; /* unsupported */ } - pf_addrcpy(naddr, &rpool->counter, af); - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - cnt = rpool->cur->addr.p.dyn->pfid_kt->pfrkt_cnt; + cnt = kt->pfrkt_cnt; if (cnt == 0) rpool->tblidx = 0; else rpool->tblidx = (int)arc4random_uniform(cnt); memset(&rpool->counter, 0, sizeof(rpool->counter)); - if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af, - pf_islinklocal)) { + if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter, + af, pf_islinklocal, false)) { reason = PFRES_MAPFAILED; goto done_pool_mtx; /* unsupported */ } @@ -671,29 +666,25 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, hashidx = pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); - if (rpool->cur->addr.type == PF_ADDR_TABLE) { - cnt = rpool->cur->addr.p.tbl->pfrkt_cnt; - if (cnt == 0) - rpool->tblidx = 0; + if (rpool->cur->addr.type == PF_ADDR_TABLE || + rpool->cur->addr.type == PF_ADDR_DYNIFTL) { + if (rpool->cur->addr.type == PF_ADDR_TABLE) + kt = rpool->cur->addr.p.tbl; else - rpool->tblidx = (int)(hashidx % cnt); - memset(&rpool->counter, 0, sizeof(rpool->counter)); - if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af, NULL)) { + kt = rpool->cur->addr.p.dyn->pfid_kt; + kt = pfr_ktable_select_active(kt); + if (kt == NULL) { reason = PFRES_MAPFAILED; goto done_pool_mtx; /* unsupported */ } - pf_addrcpy(naddr, &rpool->counter, af); - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - cnt = rpool->cur->addr.p.dyn->pfid_kt->pfrkt_cnt; + cnt = kt->pfrkt_cnt; if (cnt == 0) rpool->tblidx = 0; else rpool->tblidx = (int)(hashidx % cnt); memset(&rpool->counter, 0, sizeof(rpool->counter)); - if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af, - pf_islinklocal)) { + if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter, + af, pf_islinklocal, false)) { reason = PFRES_MAPFAILED; goto done_pool_mtx; /* unsupported */ } @@ -710,11 +701,12 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_TABLE) { if (!pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af, NULL)) + &rpool->tblidx, &rpool->counter, af, NULL, true)) goto get_addr; } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af, pf_islinklocal)) + &rpool->tblidx, &rpool->counter, af, pf_islinklocal, + true)) goto get_addr; } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) goto get_addr; @@ -724,9 +716,10 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, rpool->cur = TAILQ_FIRST(&rpool->list); else rpool->cur = TAILQ_NEXT(rpool->cur, entries); + rpool->tblidx = -1; if (rpool->cur->addr.type == PF_ADDR_TABLE) { if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af, NULL)) { + &rpool->tblidx, &rpool->counter, af, NULL, true)) { /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; @@ -734,9 +727,9 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, goto done_pool_mtx; } } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - rpool->tblidx = -1; if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af, pf_islinklocal)) { + &rpool->tblidx, &rpool->counter, af, pf_islinklocal, + true)) { /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; @@ -764,48 +757,41 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, done_pool_mtx: mtx_unlock(&rpool->mtx); - if (reason) { - counter_u64_add(V_pf_status.counters[reason], 1); - } - return (reason); } u_short pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr, - struct pf_ksrc_node **sn, struct pf_srchash **sh, struct pf_kpool *rpool, - pf_sn_types_t sn_type) + struct pf_kpool *rpool, pf_sn_types_t sn_type) { + struct pf_ksrc_node *sn = NULL; + struct pf_srchash *sh = NULL; u_short reason = 0; - KASSERT(*sn == NULL, ("*sn not NULL")); - /* * If this is a sticky-address rule, try to find an existing src_node. - * Request the sh to be unlocked if sn was not found, as we never - * insert a new sn when parsing the ruleset. */ if (rpool->opts & PF_POOL_STICKYADDR && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) - *sn = pf_find_src_node(saddr, r, af, sh, sn_type, false); + sn = pf_find_src_node(saddr, r, af, &sh, sn_type, false); - if (*sn != NULL) { - PF_SRC_NODE_LOCK_ASSERT(*sn); + if (sn != NULL) { + PF_SRC_NODE_LOCK_ASSERT(sn); /* If the supplied address is the same as the current one we've * been asked before, so tell the caller that there's no other * address to be had. */ - if (PF_AEQ(naddr, &(*sn)->raddr, af)) { + if (PF_AEQ(naddr, &(sn->raddr), af)) { reason = PFRES_MAPFAILED; goto done; } - pf_addrcpy(naddr, &(*sn)->raddr, af); + pf_addrcpy(naddr, &(sn->raddr), af); if (nkif) - *nkif = (*sn)->rkif; + *nkif = sn->rkif; if (V_pf_status.debug >= PF_DEBUG_NOISY) { - printf("pf_map_addr: src tracking maps "); + printf("%s: src tracking maps ", __func__); pf_print_host(saddr, 0, af); printf(" to "); pf_print_host(naddr, 0, af); @@ -820,14 +806,16 @@ pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, * Source node has not been found. Find a new address and store it * in variables given by the caller. */ - if (pf_map_addr(af, r, saddr, naddr, nkif, init_addr, rpool) != 0) { - /* pf_map_addr() sets reason counters on its own */ + if ((reason = pf_map_addr(af, r, saddr, naddr, nkif, init_addr, + rpool)) != 0) { + if (V_pf_status.debug >= PF_DEBUG_MISC) + printf("%s: pf_map_addr has failed\n", __func__); goto done; } if (V_pf_status.debug >= PF_DEBUG_NOISY && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { - printf("pf_map_addr: selected address "); + printf("%s: selected address ", __func__); pf_print_host(naddr, 0, af); if (nkif) printf("@%s", (*nkif)->pfik_name); @@ -835,12 +823,8 @@ pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, } done: - if ((*sn) != NULL) - PF_SRC_NODE_UNLOCK(*sn); - - if (reason) { - counter_u64_add(V_pf_status.counters[reason], 1); - } + if (sn != NULL) + PF_SRC_NODE_UNLOCK(sn); return (reason); } @@ -890,8 +874,6 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, { struct pf_pdesc *pd = ctx->pd; struct pf_addr *naddr; - struct pf_ksrc_node *sn = NULL; - struct pf_srchash *sh = NULL; uint16_t *nportp; uint16_t low, high; u_short reason; @@ -919,8 +901,8 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, high = rpool->proxy_port[1]; } if (rpool->mape.offset > 0) { - if (pf_get_mape_sport(pd, r, naddr, nportp, &sn, - &sh, &ctx->udp_mapping, rpool)) { + if (pf_get_mape_sport(pd, r, naddr, nportp, + &ctx->udp_mapping, rpool)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: MAP-E port allocation (%u/%u/%u)" " failed\n", @@ -930,8 +912,8 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, reason = PFRES_MAPFAILED; goto notrans; } - } else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn, - &sh, rpool, &ctx->udp_mapping, PF_SN_NAT)) { + } else if (pf_get_sport(pd, r, naddr, nportp, low, high, + rpool, &ctx->udp_mapping, PF_SN_NAT)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: NAT proxy port allocation (%u-%u) failed\n", rpool->proxy_port[0], rpool->proxy_port[1])); @@ -1017,7 +999,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, uint16_t cut, low, high, nport; reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL, - NULL, &sn, &sh, rpool, PF_SN_NAT); + NULL, rpool, PF_SN_NAT); if (reason != 0) goto notrans; if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) @@ -1134,8 +1116,6 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd) struct pf_addr ndaddr, nsaddr, naddr; u_int16_t nport = 0; int prefixlen = 96; - struct pf_srchash *sh = NULL; - struct pf_ksrc_node *sns = NULL; bzero(&nsaddr, sizeof(nsaddr)); bzero(&ndaddr, sizeof(ndaddr)); @@ -1154,9 +1134,8 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd) panic("pf_get_transaddr_af: no nat pool for source address"); /* get source address and port */ - if (pf_get_sport(pd, r, &nsaddr, &nport, - r->nat.proxy_port[0], r->nat.proxy_port[1], &sns, &sh, &r->nat, - NULL, PF_SN_NAT)) { + if (pf_get_sport(pd, r, &nsaddr, &nport, r->nat.proxy_port[0], + r->nat.proxy_port[1], &r->nat, NULL, PF_SN_NAT)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: af-to NAT proxy port allocation (%u-%u) failed", r->nat.proxy_port[0], r->nat.proxy_port[1])); @@ -1182,7 +1161,7 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd) /* get the destination address and port */ if (! TAILQ_EMPTY(&r->rdr.list)) { if (pf_map_addr_sn(pd->naf, r, &nsaddr, &naddr, NULL, NULL, - &sns, NULL, &r->rdr, PF_SN_NAT)) + &r->rdr, PF_SN_NAT)) return (-1); if (r->rdr.proxy_port[0]) pd->ndport = htons(r->rdr.proxy_port[0]); diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index d5d6dc70255e..73933c022ca2 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -1256,23 +1256,13 @@ pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt) return (0); } -struct pf_nl_natlook { - sa_family_t af; - uint8_t direction; - uint8_t proto; - struct pf_addr src; - struct pf_addr dst; - uint16_t sport; - uint16_t dport; -}; - -#define _OUT(_field) offsetof(struct pf_nl_natlook, _field) +#define _OUT(_field) offsetof(struct pfioc_natlook, _field) static const struct nlattr_parser nla_p_natlook[] = { { .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 }, { .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 }, { .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 }, - { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr }, - { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr }, + { .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = nlattr_get_in6_addr }, + { .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = nlattr_get_in6_addr }, { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 }, { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 }, }; @@ -1282,63 +1272,31 @@ NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook) static int pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt) { - struct pf_nl_natlook attrs = {}; - struct pf_state_key_cmp key = {}; + struct pfioc_natlook attrs = {}; struct nl_writer *nw = npt->nw; - struct pf_state_key *sk; - struct pf_kstate *state; struct genlmsghdr *ghdr_new; - int error, m = 0; - int sidx, didx; + int error; error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs); if (error != 0) return (error); - if (attrs.proto == 0 || - PF_AZERO(&attrs.src, attrs.af) || - PF_AZERO(&attrs.dst, attrs.af) || - ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) && - (attrs.sport == 0 || attrs.dport == 0))) - return (EINVAL); - - /* NATLOOK src and dst are reversed, so reverse sidx/didx */ - sidx = (attrs.direction == PF_IN) ? 1 : 0; - didx = (attrs.direction == PF_IN) ? 0 : 1; - - key.af = attrs.af; - key.proto = attrs.proto; - pf_addrcpy(&key.addr[sidx], &attrs.src, attrs.af); - key.port[sidx] = attrs.sport; - pf_addrcpy(&key.addr[didx], &attrs.dst, attrs.af); - key.port[didx] = attrs.dport; - - state = pf_find_state_all(&key, attrs.direction, &m); - if (state == NULL) - return (ENOENT); - if (m > 1) { - PF_STATE_UNLOCK(state); - return (E2BIG); - } + error = pf_ioctl_natlook(&attrs); + if (error != 0) + return (error); - if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { - PF_STATE_UNLOCK(state); + if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) return (ENOMEM); - } ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); ghdr_new->cmd = PFNL_CMD_NATLOOK; ghdr_new->version = 0; ghdr_new->reserved = 0; - sk = state->key[sidx]; - - nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6); - nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6); - nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]); - nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]); - - PF_STATE_UNLOCK(state); + nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &attrs.rsaddr.v6); + nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &attrs.rdaddr.v6); + nlattr_add_u16(nw, PF_NL_SRC_PORT, attrs.rsport); + nlattr_add_u16(nw, PF_NL_DST_PORT, attrs.rdport); if (!nlmsg_end(nw)) { nlmsg_abort(nw); diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index 43e4366845a2..9c0151b7da2b 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -819,10 +819,10 @@ pfr_create_kentry(struct pfr_addr *ad, bool counters) static void pfr_destroy_kentries(struct pfr_kentryworkq *workq) { - struct pfr_kentry *p, *q; + struct pfr_kentry *p; - for (p = SLIST_FIRST(workq); p != NULL; p = q) { - q = SLIST_NEXT(p, pfrke_workq); + while ((p = SLIST_FIRST(workq)) != NULL) { + SLIST_REMOVE_HEAD(workq, pfrke_workq); pfr_destroy_kentry(p); } } @@ -1680,8 +1680,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, } if (!(flags & PFR_FLAG_DUMMY)) { - for (p = SLIST_FIRST(&workq); p != NULL; p = q) { - q = SLIST_NEXT(p, pfrkt_workq); + SLIST_FOREACH_SAFE(p, &workq, pfrkt_workq, q) { pfr_commit_ktable(p, tzero); } rs->topen = 0; @@ -1710,7 +1709,7 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero) } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) { /* kt might contain addresses */ struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq; - struct pfr_kentry *p, *q, *next; + struct pfr_kentry *p, *q; struct pfr_addr ad; pfr_enqueue_addrs(shadow, &addrq, NULL, 0); @@ -1720,7 +1719,8 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero) SLIST_INIT(&delq); SLIST_INIT(&garbageq); pfr_clean_node_mask(shadow, &addrq); - SLIST_FOREACH_SAFE(p, &addrq, pfrke_workq, next) { + while ((p = SLIST_FIRST(&addrq)) != NULL) { + SLIST_REMOVE_HEAD(&addrq, pfrke_workq); pfr_copyout_addr(&ad, p); q = pfr_lookup_addr(kt, &ad, 1); if (q != NULL) { @@ -1864,8 +1864,7 @@ pfr_setflags_ktables(struct pfr_ktableworkq *workq) { struct pfr_ktable *p, *q; - for (p = SLIST_FIRST(workq); p; p = q) { - q = SLIST_NEXT(p, pfrkt_workq); + SLIST_FOREACH_SAFE(p, workq, pfrkt_workq, q) { pfr_setflags_ktable(p, p->pfrkt_nflags); } } @@ -2015,10 +2014,10 @@ pfr_create_ktable(struct pfr_table *tbl, time_t tzero, int attachruleset) static void pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr) { - struct pfr_ktable *p, *q; + struct pfr_ktable *p; - for (p = SLIST_FIRST(workq); p; p = q) { - q = SLIST_NEXT(p, pfrkt_workq); + while ((p = SLIST_FIRST(workq)) != NULL) { + SLIST_REMOVE_HEAD(workq, pfrkt_workq); pfr_destroy_ktable(p, flushaddr); } } @@ -2074,17 +2073,16 @@ pfr_lookup_table(struct pfr_table *tbl) (struct pfr_ktable *)tbl)); } -int -pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) +static struct pfr_kentry * +pfr_kentry_byaddr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, + int exact) { struct pfr_kentry *ke = NULL; - int match; PF_RULES_RASSERT(); - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) - kt = kt->pfrkt_root; - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) + kt = pfr_ktable_select_active(kt); + if (kt == NULL) return (0); switch (af) { @@ -2121,11 +2119,26 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) default: unhandled_af(af); } + if (exact && ke && KENTRY_NETWORK(ke)) + ke = NULL; + + return (ke); +} + +int +pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) +{ + struct pfr_kentry *ke = NULL; + int match; + + ke = pfr_kentry_byaddr(kt, a, af, 0); + match = (ke && !ke->pfrke_not); if (match) pfr_kstate_counter_add(&kt->pfrkt_match, 1); else pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); + return (match); } @@ -2135,9 +2148,8 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, { struct pfr_kentry *ke = NULL; - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) - kt = kt->pfrkt_root; - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) + kt = pfr_ktable_select_active(kt); + if (kt == NULL) return; switch (af) { @@ -2281,7 +2293,7 @@ pfr_detach_table(struct pfr_ktable *kt) int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, - sa_family_t af, pf_addr_filter_func_t filter) + sa_family_t af, pf_addr_filter_func_t filter, bool loop_once) { struct pf_addr *addr, cur, mask, umask_addr; union sockaddr_union uaddr, umask; @@ -2306,9 +2318,8 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, unhandled_af(af); } - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) - kt = kt->pfrkt_root; - if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) + kt = pfr_ktable_select_active(kt); + if (kt == NULL) return (-1); idx = *pidx; @@ -2327,7 +2338,7 @@ _next_block: ke = pfr_kentry_byidx(kt, idx, af); if (ke == NULL) { /* we don't have this idx, try looping */ - if (loop || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) { + if ((loop || loop_once) || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) { pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); return (1); } @@ -2455,3 +2466,14 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) unhandled_af(dyn->pfid_af); } } + +struct pfr_ktable * +pfr_ktable_select_active(struct pfr_ktable *kt) +{ + if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) + kt = kt->pfrkt_root; + if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) + return (NULL); + + return (kt); +} diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 7746b668265d..ae17b3289593 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -1469,6 +1469,9 @@ moea_page_set_memattr(vm_page_t m, vm_memattr_t ma) pmap_t pmap; u_int lo; + if (m->md.mdpg_cache_attrs == ma) + return; + if ((m->oflags & VPO_UNMANAGED) != 0) { m->md.mdpg_cache_attrs = ma; return; diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 79cea408bb5f..796b1719b8ba 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -2134,6 +2134,9 @@ moea64_page_set_memattr(vm_page_t m, vm_memattr_t ma) CTR3(KTR_PMAP, "%s: pa=%#jx, ma=%#x", __func__, (uintmax_t)VM_PAGE_TO_PHYS(m), ma); + if (m->md.mdpg_cache_attrs == ma) + return; + if ((m->oflags & VPO_UNMANAGED) != 0) { m->md.mdpg_cache_attrs = ma; return; diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c index 45f7bef8bcc9..a12142fc2d7b 100644 --- a/sys/powerpc/aim/mmu_radix.c +++ b/sys/powerpc/aim/mmu_radix.c @@ -5937,6 +5937,10 @@ mmu_radix_page_set_memattr(vm_page_t m, vm_memattr_t ma) { CTR3(KTR_PMAP, "%s(%p, %#x)", __func__, m, ma); + + if (m->md.mdpg_cache_attrs == ma) + return; + m->md.mdpg_cache_attrs = ma; /* diff --git a/sys/powerpc/include/pcb.h b/sys/powerpc/include/pcb.h index 050ada6b0f64..0230cf78aba7 100644 --- a/sys/powerpc/include/pcb.h +++ b/sys/powerpc/include/pcb.h @@ -66,16 +66,8 @@ struct pcb { #define PCB_VECREGS 0x200 /* Process had Altivec registers initialized */ struct fpu { union { -#if _BYTE_ORDER == _BIG_ENDIAN - double fpr; - uint32_t vsr[4]; -#else uint32_t vsr[4]; - struct { - double padding; - double fpr; - }; -#endif + double fpr; } fpr[32]; double fpscr; /* FPSCR stored as double for easier access */ } pcb_fpu; /* Floating point processor */ diff --git a/sys/powerpc/include/ucontext.h b/sys/powerpc/include/ucontext.h index d35c6c773fe0..dc87edd578bc 100644 --- a/sys/powerpc/include/ucontext.h +++ b/sys/powerpc/include/ucontext.h @@ -41,6 +41,7 @@ typedef struct __mcontext { int mc_flags; #define _MC_FP_VALID 0x01 #define _MC_AV_VALID 0x02 +#define _MC_VS_VALID 0x04 int mc_onstack; /* saved onstack flag */ int mc_len; /* sizeof(__mcontext) */ __uint64_t mc_avec[32*2]; /* vector register file */ @@ -56,6 +57,7 @@ typedef struct __mcontext32 { int mc_flags; #define _MC_FP_VALID 0x01 #define _MC_AV_VALID 0x02 +#define _MC_VS_VALID 0x04 int mc_onstack; /* saved onstack flag */ int mc_len; /* sizeof(__mcontext) */ uint64_t mc_avec[32*2]; /* vector register file */ diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c index 1893d79f29a8..8a33d0f589a7 100644 --- a/sys/powerpc/powerpc/exec_machdep.c +++ b/sys/powerpc/powerpc/exec_machdep.c @@ -214,10 +214,10 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sfpsize = sizeof(sf); #ifdef __powerpc64__ /* - * 64-bit PPC defines a 288 byte scratch region - * below the stack. + * 64-bit PPC defines a 512 byte red zone below + * the existing stack (ELF ABI v2 §2.2.2.4) */ - rndfsize = 288 + roundup(sizeof(sf), 48); + rndfsize = 512 + roundup(sizeof(sf), 48); #else rndfsize = roundup(sizeof(sf), 16); #endif @@ -349,13 +349,6 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap) if (error != 0) return (error); - /* - * Save FPU state if needed. User may have changed it on - * signal handler - */ - if (uc.uc_mcontext.mc_srr1 & PSL_FP) - save_fpu(td); - kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x", @@ -432,6 +425,7 @@ grab_mcontext(struct thread *td, mcontext_t *mcp, int flags) } if (pcb->pcb_flags & PCB_VSX) { + mcp->mc_flags |= _MC_VS_VALID; for (i = 0; i < 32; i++) memcpy(&mcp->mc_vsxfpreg[i], &pcb->pcb_fpu.fpr[i].vsr[2], sizeof(double)); @@ -481,6 +475,7 @@ set_mcontext(struct thread *td, mcontext_t *mcp) struct pcb *pcb; struct trapframe *tf; register_t tls; + register_t msr; int i; pcb = td->td_pcb; @@ -531,6 +526,22 @@ set_mcontext(struct thread *td, mcontext_t *mcp) tf->srr1 &= ~(PSL_FP | PSL_VSX | PSL_VEC); pcb->pcb_flags &= ~(PCB_FPU | PCB_VSX | PCB_VEC); + /* + * Ensure the FPU is also disabled in hardware. + * + * Without this, it's possible for the register reload to fail if we + * don't switch to a FPU disabled context before resuming the original + * thread. Specifically, if the FPU/VSX unavailable exception is never + * hit, then whatever data is still in the FP/VSX registers when + * sigresume is callled will used by the resumed thread, instead of the + * previously saved data from the mcontext. + */ + critical_enter(); + msr = mfmsr() & ~(PSL_FP | PSL_VSX | PSL_VEC); + isync(); + mtmsr(msr); + critical_exit(); + if (mcp->mc_flags & _MC_FP_VALID) { /* enable_fpu() will happen lazily on a fault */ pcb->pcb_flags |= PCB_FPREGS; @@ -539,8 +550,12 @@ set_mcontext(struct thread *td, mcontext_t *mcp) for (i = 0; i < 32; i++) { memcpy(&pcb->pcb_fpu.fpr[i].fpr, &mcp->mc_fpreg[i], sizeof(double)); - memcpy(&pcb->pcb_fpu.fpr[i].vsr[2], - &mcp->mc_vsxfpreg[i], sizeof(double)); + } + if (mcp->mc_flags & _MC_VS_VALID) { + for (i = 0; i < 32; i++) { + memcpy(&pcb->pcb_fpu.fpr[i].vsr[2], + &mcp->mc_vsxfpreg[i], sizeof(double)); + } } } diff --git a/sys/powerpc/powerpc/fpu.c b/sys/powerpc/powerpc/fpu.c index 0eaff2ea4932..cc8f22f7dda3 100644 --- a/sys/powerpc/powerpc/fpu.c +++ b/sys/powerpc/powerpc/fpu.c @@ -64,8 +64,19 @@ save_fpu_int(struct thread *td) * Save the floating-point registers and FPSCR to the PCB */ if (pcb->pcb_flags & PCB_VSX) { - #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \ +#if _BYTE_ORDER == _BIG_ENDIAN + #define SFP(n) __asm("stxvw4x " #n ", 0,%0" \ :: "b"(&pcb->pcb_fpu.fpr[n])); +#else + /* + * stxvw2x will swap words within the FP double word on LE systems, + * leading to corruption if VSX is used to store state and FP is + * subsequently used to restore state. + * Use stxvd2x instead. + */ + #define SFP(n) __asm("stxvd2x " #n ", 0,%0" \ + :: "b"(&pcb->pcb_fpu.fpr[n])); +#endif SFP(0); SFP(1); SFP(2); SFP(3); SFP(4); SFP(5); SFP(6); SFP(7); SFP(8); SFP(9); SFP(10); SFP(11); @@ -76,7 +87,7 @@ save_fpu_int(struct thread *td) SFP(28); SFP(29); SFP(30); SFP(31); #undef SFP } else { - #define SFP(n) __asm ("stfd " #n ", 0(%0)" \ + #define SFP(n) __asm("stfd " #n ", 0(%0)" \ :: "b"(&pcb->pcb_fpu.fpr[n].fpr)); SFP(0); SFP(1); SFP(2); SFP(3); SFP(4); SFP(5); SFP(6); SFP(7); @@ -149,8 +160,19 @@ enable_fpu(struct thread *td) :: "b"(&pcb->pcb_fpu.fpscr)); if (pcb->pcb_flags & PCB_VSX) { - #define LFP(n) __asm ("lxvw4x " #n ", 0,%0" \ +#if _BYTE_ORDER == _BIG_ENDIAN + #define LFP(n) __asm("lxvw4x " #n ", 0,%0" \ + :: "b"(&pcb->pcb_fpu.fpr[n])); +#else + /* + * lxvw4x will swap words within the FP double word on LE systems, + * leading to corruption if FP is used to store state and VSX is + * subsequently used to restore state. + * Use lxvd2x instead. + */ + #define LFP(n) __asm("lxvd2x " #n ", 0,%0" \ :: "b"(&pcb->pcb_fpu.fpr[n])); +#endif LFP(0); LFP(1); LFP(2); LFP(3); LFP(4); LFP(5); LFP(6); LFP(7); LFP(8); LFP(9); LFP(10); LFP(11); @@ -161,7 +183,7 @@ enable_fpu(struct thread *td) LFP(28); LFP(29); LFP(30); LFP(31); #undef LFP } else { - #define LFP(n) __asm ("lfd " #n ", 0(%0)" \ + #define LFP(n) __asm("lfd " #n ", 0(%0)" \ :: "b"(&pcb->pcb_fpu.fpr[n].fpr)); LFP(0); LFP(1); LFP(2); LFP(3); LFP(4); LFP(5); LFP(6); LFP(7); diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c index 5d15bd671285..26efaecc64d1 100644 --- a/sys/riscv/riscv/pmap.c +++ b/sys/riscv/riscv/pmap.c @@ -4838,6 +4838,8 @@ pmap_unmapbios(void *p, vm_size_t size) void pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) { + if (m->md.pv_memattr == ma) + return; m->md.pv_memattr = ma; diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index 87460aae2dd4..efda38279848 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -306,7 +306,7 @@ typedef struct { and MPRC of Peking University */ #define EM_AARCH64 183 /* AArch64 (64-bit ARM) */ #define EM_RISCV 243 /* RISC-V */ -#define EM_LOONGARCH 258 /* Loongson LoongArch */ +#define EM_LOONGARCH 258 /* Loongson LoongArch */ /* Non-standard or deprecated. */ #define EM_486 6 /* Intel i486. */ @@ -392,15 +392,15 @@ typedef struct { */ /* LoongArch Base ABI Modifiers */ -#define EF_LOONGARCH_ABI_SOFT_FLOAT 0x00000001 -#define EF_LOONGARCH_ABI_SINGLE_FLOAT 0x00000002 -#define EF_LOONGARCH_ABI_DOUBLE_FLOAT 0x00000003 -#define EF_LOONGARCH_ABI_MODIFIER_MASK 0x00000007 +#define EF_LOONGARCH_ABI_SOFT_FLOAT 0x00000001 +#define EF_LOONGARCH_ABI_SINGLE_FLOAT 0x00000002 +#define EF_LOONGARCH_ABI_DOUBLE_FLOAT 0x00000003 +#define EF_LOONGARCH_ABI_MODIFIER_MASK 0x00000007 /* LoongArch Object file ABI versions */ -#define EF_LOONGARCH_OBJABI_V0 0x00000000 -#define EF_LOONGARCH_OBJABI_V1 0x00000040 -#define EF_LOONGARCH_OBJABI_MASK 0x000000C0 +#define EF_LOONGARCH_OBJABI_V0 0x00000000 +#define EF_LOONGARCH_OBJABI_V1 0x00000040 +#define EF_LOONGARCH_OBJABI_MASK 0x000000C0 #define EF_SPARC_EXT_MASK 0x00ffff00 #define EF_SPARC_32PLUS 0x00000100 @@ -470,12 +470,12 @@ typedef struct { #define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ #define SHT_LOPROC 0x70000000 /* reserved range for processor */ #define SHT_X86_64_UNWIND 0x70000001 /* unwind information */ -#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND +#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND #define SHT_ARM_EXIDX 0x70000001 /* Exception index table. */ -#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking +#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map. */ -#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility +#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes. */ #define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details. */ #define SHT_ARM_OVERLAYSECTION 0x70000005 /* See DBGOVL for details. */ @@ -791,7 +791,7 @@ typedef struct { #define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */ #define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filtees */ #define DF_1_INITFIRST 0x00000020 /* Initialize DSO first at runtime */ -#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ +#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ #define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */ #define DF_1_INTERPOSE 0x00000400 /* Interpose all objects but main */ #define DF_1_NODEFLIB 0x00000800 /* Do not search default paths */ @@ -908,7 +908,7 @@ typedef struct { #define STV_ELIMINATE 0x6 /* Architecture specific data - st_other */ -#define STO_AARCH64_VARIANT_PCS 0x80 +#define STO_AARCH64_VARIANT_PCS 0x80 /* Special symbol table indexes. */ #define STN_UNDEF 0 /* Undefined symbol index. */ @@ -1084,11 +1084,11 @@ typedef struct { #define R_AARCH64_COPY 1024 /* Copy data from shared object */ #define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address */ #define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address */ -#define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */ +#define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */ #define R_AARCH64_TLS_DTPREL64 1028 #define R_AARCH64_TLS_DTPMOD64 1029 -#define R_AARCH64_TLS_TPREL64 1030 -#define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */ +#define R_AARCH64_TLS_TPREL64 1030 +#define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */ #define R_AARCH64_IRELATIVE 1032 #define R_ARM_NONE 0 /* No relocation. */ @@ -1231,8 +1231,8 @@ typedef struct { #define R_MIPS_GOT_HI16 22 /* GOT HI 16 bit */ #define R_MIPS_GOT_LO16 23 /* GOT LO 16 bit */ #define R_MIPS_SUB 24 -#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ -#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ +#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ +#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ #define R_MIPS_JALR 37 #define R_MIPS_TLS_GD 42 #define R_MIPS_COPY 126 @@ -1352,7 +1352,6 @@ typedef struct { * RISC-V relocation types. */ -/* Relocation types used by the dynamic linker. */ #define R_RISCV_NONE 0 #define R_RISCV_32 1 #define R_RISCV_64 2 @@ -1365,8 +1364,7 @@ typedef struct { #define R_RISCV_TLS_DTPREL64 9 #define R_RISCV_TLS_TPREL32 10 #define R_RISCV_TLS_TPREL64 11 - -/* Relocation types not used by the dynamic linker. */ +#define R_RISCV_TLSDESC 12 #define R_RISCV_BRANCH 16 #define R_RISCV_JAL 17 #define R_RISCV_CALL 18 @@ -1392,10 +1390,10 @@ typedef struct { #define R_RISCV_SUB16 38 #define R_RISCV_SUB32 39 #define R_RISCV_SUB64 40 +#define R_RISCV_GOT32_PCREL 41 #define R_RISCV_ALIGN 43 #define R_RISCV_RVC_BRANCH 44 #define R_RISCV_RVC_JUMP 45 -#define R_RISCV_RVC_LUI 46 #define R_RISCV_RELAX 51 #define R_RISCV_SUB6 52 #define R_RISCV_SET6 53 @@ -1404,6 +1402,14 @@ typedef struct { #define R_RISCV_SET32 56 #define R_RISCV_32_PCREL 57 #define R_RISCV_IRELATIVE 58 +#define R_RISCV_PLT32 59 +#define R_RISCV_SET_ULEB128 60 +#define R_RISCV_SUB_ULEB128 61 +#define R_RISCV_TLSDESC_HI20 62 +#define R_RISCV_TLSDESC_LOAD_LO12 63 +#define R_RISCV_TLSDESC_ADD_LO12 64 +#define R_RISCV_TLSDESC_CALL 65 +#define R_RISCV_VENDOR 191 /* * Loongson LoongArch relocation types. @@ -1413,101 +1419,101 @@ typedef struct { */ /* Relocation types used by the dynamic linker */ -#define R_LARCH_NONE 0 -#define R_LARCH_32 1 -#define R_LARCH_64 2 -#define R_LARCH_RELATIVE 3 -#define R_LARCH_COPY 4 -#define R_LARCH_JUMP_SLOT 5 -#define R_LARCH_TLS_DTPMOD32 6 -#define R_LARCH_TLS_DTPMOD64 7 -#define R_LARCH_TLS_DTPREL32 8 -#define R_LARCH_TLS_DTPREL64 9 -#define R_LARCH_TLS_TPREL32 10 -#define R_LARCH_TLS_TPREL64 11 -#define R_LARCH_IRELATIVE 12 -#define R_LARCH_MARK_LA 20 -#define R_LARCH_MARK_PCREL 21 -#define R_LARCH_SOP_PUSH_PCREL 22 -#define R_LARCH_SOP_PUSH_ABSOLUTE 23 -#define R_LARCH_SOP_PUSH_DUP 24 -#define R_LARCH_SOP_PUSH_GPREL 25 -#define R_LARCH_SOP_PUSH_TLS_TPREL 26 -#define R_LARCH_SOP_PUSH_TLS_GOT 27 -#define R_LARCH_SOP_PUSH_TLS_GD 28 -#define R_LARCH_SOP_PUSH_PLT_PCREL 29 -#define R_LARCH_SOP_ASSERT 30 -#define R_LARCH_SOP_NOT 31 -#define R_LARCH_SOP_SUB 32 -#define R_LARCH_SOP_SL 33 -#define R_LARCH_SOP_SR 34 -#define R_LARCH_SOP_ADD 35 -#define R_LARCH_SOP_AND 36 -#define R_LARCH_SOP_IF_ELSE 37 -#define R_LARCH_SOP_POP_32_S_10_5 38 -#define R_LARCH_SOP_POP_32_U_10_12 39 -#define R_LARCH_SOP_POP_32_S_10_12 40 -#define R_LARCH_SOP_POP_32_S_10_16 41 -#define R_LARCH_SOP_POP_32_S_10_16_S2 42 -#define R_LARCH_SOP_POP_32_S_5_20 43 -#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 -#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 -#define R_LARCH_SOP_POP_32_U 46 -#define R_LARCH_ADD8 47 -#define R_LARCH_ADD16 48 -#define R_LARCH_ADD24 49 -#define R_LARCH_ADD32 50 -#define R_LARCH_ADD64 51 -#define R_LARCH_SUB8 52 -#define R_LARCH_SUB16 53 -#define R_LARCH_SUB24 54 -#define R_LARCH_SUB32 55 -#define R_LARCH_SUB64 56 -#define R_LARCH_GNU_VTINHERIT 57 -#define R_LARCH_GNU_VTENTRY 58 +#define R_LARCH_NONE 0 +#define R_LARCH_32 1 +#define R_LARCH_64 2 +#define R_LARCH_RELATIVE 3 +#define R_LARCH_COPY 4 +#define R_LARCH_JUMP_SLOT 5 +#define R_LARCH_TLS_DTPMOD32 6 +#define R_LARCH_TLS_DTPMOD64 7 +#define R_LARCH_TLS_DTPREL32 8 +#define R_LARCH_TLS_DTPREL64 9 +#define R_LARCH_TLS_TPREL32 10 +#define R_LARCH_TLS_TPREL64 11 +#define R_LARCH_IRELATIVE 12 +#define R_LARCH_MARK_LA 20 +#define R_LARCH_MARK_PCREL 21 +#define R_LARCH_SOP_PUSH_PCREL 22 +#define R_LARCH_SOP_PUSH_ABSOLUTE 23 +#define R_LARCH_SOP_PUSH_DUP 24 +#define R_LARCH_SOP_PUSH_GPREL 25 +#define R_LARCH_SOP_PUSH_TLS_TPREL 26 +#define R_LARCH_SOP_PUSH_TLS_GOT 27 +#define R_LARCH_SOP_PUSH_TLS_GD 28 +#define R_LARCH_SOP_PUSH_PLT_PCREL 29 +#define R_LARCH_SOP_ASSERT 30 +#define R_LARCH_SOP_NOT 31 +#define R_LARCH_SOP_SUB 32 +#define R_LARCH_SOP_SL 33 +#define R_LARCH_SOP_SR 34 +#define R_LARCH_SOP_ADD 35 +#define R_LARCH_SOP_AND 36 +#define R_LARCH_SOP_IF_ELSE 37 +#define R_LARCH_SOP_POP_32_S_10_5 38 +#define R_LARCH_SOP_POP_32_U_10_12 39 +#define R_LARCH_SOP_POP_32_S_10_12 40 +#define R_LARCH_SOP_POP_32_S_10_16 41 +#define R_LARCH_SOP_POP_32_S_10_16_S2 42 +#define R_LARCH_SOP_POP_32_S_5_20 43 +#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 +#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 +#define R_LARCH_SOP_POP_32_U 46 +#define R_LARCH_ADD8 47 +#define R_LARCH_ADD16 48 +#define R_LARCH_ADD24 49 +#define R_LARCH_ADD32 50 +#define R_LARCH_ADD64 51 +#define R_LARCH_SUB8 52 +#define R_LARCH_SUB16 53 +#define R_LARCH_SUB24 54 +#define R_LARCH_SUB32 55 +#define R_LARCH_SUB64 56 +#define R_LARCH_GNU_VTINHERIT 57 +#define R_LARCH_GNU_VTENTRY 58 /* * Relocs whose processing do not require a stack machine. * * Spec addition: https://github.com/loongson/LoongArch-Documentation/pull/57 */ -#define R_LARCH_B16 64 -#define R_LARCH_B21 65 -#define R_LARCH_B26 66 -#define R_LARCH_ABS_HI20 67 -#define R_LARCH_ABS_LO12 68 -#define R_LARCH_ABS64_LO20 69 -#define R_LARCH_ABS64_HI12 70 -#define R_LARCH_PCALA_HI20 71 -#define R_LARCH_PCALA_LO12 72 -#define R_LARCH_PCALA64_LO20 73 -#define R_LARCH_PCALA64_HI12 74 -#define R_LARCH_GOT_PC_HI20 75 -#define R_LARCH_GOT_PC_LO12 76 -#define R_LARCH_GOT64_PC_LO20 77 -#define R_LARCH_GOT64_PC_HI12 78 -#define R_LARCH_GOT_HI20 79 -#define R_LARCH_GOT_LO12 80 -#define R_LARCH_GOT64_LO20 81 -#define R_LARCH_GOT64_HI12 82 -#define R_LARCH_TLS_LE_HI20 83 -#define R_LARCH_TLS_LE_LO12 84 -#define R_LARCH_TLS_LE64_LO20 85 -#define R_LARCH_TLS_LE64_HI12 86 -#define R_LARCH_TLS_IE_PC_HI20 87 -#define R_LARCH_TLS_IE_PC_LO12 88 -#define R_LARCH_TLS_IE64_PC_LO20 89 -#define R_LARCH_TLS_IE64_PC_HI12 90 -#define R_LARCH_TLS_IE_HI20 91 -#define R_LARCH_TLS_IE_LO12 92 -#define R_LARCH_TLS_IE64_LO20 93 -#define R_LARCH_TLS_IE64_HI12 94 -#define R_LARCH_TLS_LD_PC_HI20 95 -#define R_LARCH_TLS_LD_HI20 96 -#define R_LARCH_TLS_GD_PC_HI20 97 -#define R_LARCH_TLS_GD_HI20 98 -#define R_LARCH_32_PCREL 99 -#define R_LARCH_RELAX 100 +#define R_LARCH_B16 64 +#define R_LARCH_B21 65 +#define R_LARCH_B26 66 +#define R_LARCH_ABS_HI20 67 +#define R_LARCH_ABS_LO12 68 +#define R_LARCH_ABS64_LO20 69 +#define R_LARCH_ABS64_HI12 70 +#define R_LARCH_PCALA_HI20 71 +#define R_LARCH_PCALA_LO12 72 +#define R_LARCH_PCALA64_LO20 73 +#define R_LARCH_PCALA64_HI12 74 +#define R_LARCH_GOT_PC_HI20 75 +#define R_LARCH_GOT_PC_LO12 76 +#define R_LARCH_GOT64_PC_LO20 77 +#define R_LARCH_GOT64_PC_HI12 78 +#define R_LARCH_GOT_HI20 79 +#define R_LARCH_GOT_LO12 80 +#define R_LARCH_GOT64_LO20 81 +#define R_LARCH_GOT64_HI12 82 +#define R_LARCH_TLS_LE_HI20 83 +#define R_LARCH_TLS_LE_LO12 84 +#define R_LARCH_TLS_LE64_LO20 85 +#define R_LARCH_TLS_LE64_HI12 86 +#define R_LARCH_TLS_IE_PC_HI20 87 +#define R_LARCH_TLS_IE_PC_LO12 88 +#define R_LARCH_TLS_IE64_PC_LO20 89 +#define R_LARCH_TLS_IE64_PC_HI12 90 +#define R_LARCH_TLS_IE_HI20 91 +#define R_LARCH_TLS_IE_LO12 92 +#define R_LARCH_TLS_IE64_LO20 93 +#define R_LARCH_TLS_IE64_HI12 94 +#define R_LARCH_TLS_LD_PC_HI20 95 +#define R_LARCH_TLS_LD_HI20 96 +#define R_LARCH_TLS_GD_PC_HI20 97 +#define R_LARCH_TLS_GD_HI20 98 +#define R_LARCH_32_PCREL 99 +#define R_LARCH_RELAX 100 /* * Relocs added in ELF for the LoongArch™ Architecture v20230519, part of the @@ -1520,13 +1526,13 @@ typedef struct { * in psABI v2.20 because they were proved not necessary to be exposed outside * of the linker. */ -#define R_LARCH_ALIGN 102 -#define R_LARCH_PCREL20_S2 103 -#define R_LARCH_ADD6 105 -#define R_LARCH_SUB6 106 -#define R_LARCH_ADD_ULEB128 107 -#define R_LARCH_SUB_ULEB128 108 -#define R_LARCH_64_PCREL 109 +#define R_LARCH_ALIGN 102 +#define R_LARCH_PCREL20_S2 103 +#define R_LARCH_ADD6 105 +#define R_LARCH_SUB6 106 +#define R_LARCH_ADD_ULEB128 107 +#define R_LARCH_SUB_ULEB128 108 +#define R_LARCH_64_PCREL 109 /* * Relocs added in ELF for the LoongArch™ Architecture v20231102, part of the @@ -1534,7 +1540,7 @@ typedef struct { * * Spec addition: https://github.com/loongson/la-abi-specs/pull/4 */ -#define R_LARCH_CALL36 110 +#define R_LARCH_CALL36 110 /* * Relocs added in ELF for the LoongArch™ Architecture v20231219, part of the @@ -1542,24 +1548,24 @@ typedef struct { * * Spec addition: https://github.com/loongson/la-abi-specs/pull/5 */ -#define R_LARCH_TLS_DESC32 13 -#define R_LARCH_TLS_DESC64 14 -#define R_LARCH_TLS_DESC_PC_HI20 111 -#define R_LARCH_TLS_DESC_PC_LO12 112 -#define R_LARCH_TLS_DESC64_PC_LO20 113 -#define R_LARCH_TLS_DESC64_PC_HI12 114 -#define R_LARCH_TLS_DESC_HI20 115 -#define R_LARCH_TLS_DESC_LO12 116 -#define R_LARCH_TLS_DESC64_LO20 117 -#define R_LARCH_TLS_DESC64_HI12 118 -#define R_LARCH_TLS_DESC_LD 119 -#define R_LARCH_TLS_DESC_CALL 120 -#define R_LARCH_TLS_LE_HI20_R 121 -#define R_LARCH_TLS_LE_ADD_R 122 -#define R_LARCH_TLS_LE_LO12_R 123 -#define R_LARCH_TLS_LD_PCREL20_S2 124 -#define R_LARCH_TLS_GD_PCREL20_S2 125 -#define R_LARCH_TLS_DESC_PCREL20_S2 126 +#define R_LARCH_TLS_DESC32 13 +#define R_LARCH_TLS_DESC64 14 +#define R_LARCH_TLS_DESC_PC_HI20 111 +#define R_LARCH_TLS_DESC_PC_LO12 112 +#define R_LARCH_TLS_DESC64_PC_LO20 113 +#define R_LARCH_TLS_DESC64_PC_HI12 114 +#define R_LARCH_TLS_DESC_HI20 115 +#define R_LARCH_TLS_DESC_LO12 116 +#define R_LARCH_TLS_DESC64_LO20 117 +#define R_LARCH_TLS_DESC64_HI12 118 +#define R_LARCH_TLS_DESC_LD 119 +#define R_LARCH_TLS_DESC_CALL 120 +#define R_LARCH_TLS_LE_HI20_R 121 +#define R_LARCH_TLS_LE_ADD_R 122 +#define R_LARCH_TLS_LE_LO12_R 123 +#define R_LARCH_TLS_LD_PCREL20_S2 124 +#define R_LARCH_TLS_GD_PCREL20_S2 125 +#define R_LARCH_TLS_DESC_PCREL20_S2 126 #define R_SPARC_NONE 0 #define R_SPARC_8 1 diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h index 15557c614f88..7bf1d264ff5e 100644 --- a/sys/sys/exterrvar.h +++ b/sys/sys/exterrvar.h @@ -21,6 +21,7 @@ #define EXTERRCTL_ENABLE 1 #define EXTERRCTL_DISABLE 2 +#define EXTERRCTL_UD 3 #define EXTERRCTLF_FORCE 0x00000001 diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index dd9fccf5cf38..18d3928e91c7 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -144,6 +144,10 @@ typedef __pid_t pid_t; #define O_XATTR O_NAMEDATTR /* Solaris compatibility */ #endif +#if __POSIX_VISIBLE >= 202405 +#define O_CLOFORK 0x08000000 +#endif + /* * !!! DANGER !!! * @@ -280,6 +284,16 @@ typedef __pid_t pid_t; #define F_GET_SEALS 20 #define F_ISUNIONSTACK 21 /* Kludge for libc, don't use it. */ #define F_KINFO 22 /* Return kinfo_file for this fd */ +#endif /* __BSD_VISIBLE */ + +#if __POSIX_VISIBLE >= 202405 +#define F_DUPFD_CLOFORK 23 /* Like F_DUPFD, but FD_CLOFORK is set */ +#endif + +#if __BSD_VISIBLE +#define F_DUP3FD 24 /* Used with dup3() */ + +#define F_DUP3FD_SHIFT 16 /* Shift used for F_DUP3FD */ /* Seals (F_ADD_SEALS, F_GET_SEALS). */ #define F_SEAL_SEAL 0x0001 /* Prevent adding sealings */ @@ -292,6 +306,9 @@ typedef __pid_t pid_t; #define FD_CLOEXEC 1 /* close-on-exec flag */ #define FD_RESOLVE_BENEATH 2 /* all lookups relative to fd have O_RESOLVE_BENEATH semantics */ +#if __POSIX_VISIBLE >= 202405 +#define FD_CLOFORK 4 /* close-on-fork flag */ +#endif /* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */ #define F_RDLCK 1 /* shared or read lock */ diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 55969b2ff4b3..0a388c90de26 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -149,6 +149,7 @@ struct filedesc_to_leader { */ #define UF_EXCLOSE 0x01 /* auto-close on exec */ #define UF_RESOLVE_BENEATH 0x02 /* lookups must be beneath this dir */ +#define UF_FOCLOSE 0x04 /* auto-close on fork */ #ifdef _KERNEL @@ -221,6 +222,7 @@ enum { /* Flags for kern_dup(). */ #define FDDUP_FLAG_CLOEXEC 0x1 /* Atomically set UF_EXCLOSE. */ +#define FDDUP_FLAG_CLOFORK 0x2 /* Atomically set UF_FOCLOSE. */ /* For backward compatibility. */ #define falloc(td, resultfp, resultfd, flags) \ diff --git a/sys/sys/param.h b/sys/sys/param.h index af116d6e3f7a..a8e9635242dd 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -74,7 +74,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1500051 +#define __FreeBSD_version 1500052 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/socket.h b/sys/sys/socket.h index 5e7c554c34cf..cdd4fa3b4b89 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -111,10 +111,11 @@ typedef __uintptr_t uintptr_t; */ #define SOCK_CLOEXEC 0x10000000 #define SOCK_NONBLOCK 0x20000000 +#define SOCK_CLOFORK 0x40000000 #ifdef _KERNEL /* * Flags for accept1(), kern_accept4() and solisten_dequeue, in addition - * to SOCK_CLOEXEC and SOCK_NONBLOCK. + * to SOCK_CLOEXEC, SOCK_CLOFORK and SOCK_NONBLOCK. */ #define ACCEPT4_INHERIT 0x1 #define ACCEPT4_COMPAT 0x2 @@ -478,6 +479,9 @@ struct msghdr { #define MSG_MORETOCOME 0x00100000 /* additional data pending */ #define MSG_TLSAPPDATA 0x00200000 /* do not soreceive() alert rec. (TLS) */ #endif +#if __BSD_VISIBLE +#define MSG_CMSG_CLOFORK 0x00400000 /* make received fds close-on-fork */ +#endif /* * Header for ancillary data objects in msg_control buffer. diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index fe6dd9e14fb4..fd183ffbc7a4 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -257,6 +257,7 @@ int kern_munlock(struct thread *td, uintptr_t addr, size_t size); int kern_munmap(struct thread *td, uintptr_t addr, size_t size); int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt); +int kern_nosys(struct thread *td, int dummy); int kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp); int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, long *ploff); diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 6314b03142e7..4ddfc8516053 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -79,11 +79,10 @@ struct sysent { /* system call table */ */ #define SYF_CAPENABLED 0x00000001 -#define SY_THR_FLAGMASK 0x7 -#define SY_THR_STATIC 0x1 -#define SY_THR_DRAINING 0x2 -#define SY_THR_ABSENT 0x4 -#define SY_THR_INCR 0x8 +#define SY_THR_STATIC 0x01 +#define SY_THR_DRAINING 0x02 +#define SY_THR_ABSENT 0x04 +#define SY_THR_INCR 0x08 #ifdef KLD_MODULE #define SY_THR_STATIC_KLD 0 diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h index f5caea2e3919..c291c1dc2b95 100644 --- a/sys/sys/unistd.h +++ b/sys/sys/unistd.h @@ -156,6 +156,7 @@ #define _PC_DEALLOC_PRESENT 65 #define _PC_NAMEDATTR_ENABLED 66 #define _PC_HAS_NAMEDATTR 67 +#define _PC_HAS_HIDDENSYSTEM 68 #endif /* From OpenSolaris, used by SEEK_DATA/SEEK_HOLE. */ @@ -210,6 +211,7 @@ * close_range() options. */ #define CLOSE_RANGE_CLOEXEC (1<<2) +#define CLOSE_RANGE_CLOFORK (1<<3) #endif /* __BSD_VISIBLE */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 3ed469bdce6d..2c6947103c94 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1032,7 +1032,7 @@ void vop_rename_fail(struct vop_rename_args *ap); #define VOP_WRITE_POST(ap, ret) \ noffset = (ap)->a_uio->uio_offset; \ if (noffset > ooffset) { \ - if (VN_KNLIST_EMPTY((ap)->a_vp)) { \ + if (!VN_KNLIST_EMPTY((ap)->a_vp)) { \ VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE | \ (noffset > osize ? NOTE_EXTEND : 0)); \ } \ diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 74cb094bdfe4..53fac4b0665e 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -2720,6 +2720,9 @@ ufs_pathconf( case _PC_SYMLINK_MAX: *ap->a_retval = MAXPATHLEN; break; + case _PC_HAS_HIDDENSYSTEM: + *ap->a_retval = 1; + break; default: error = vop_stdpathconf(ap); diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 86b75a2d7989..d6bd06226d04 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -384,8 +384,8 @@ swap_release_by_cred(vm_ooffset_t decr, struct ucred *cred) #endif } -static int swap_pager_full = 2; /* swap space exhaustion (task killing) */ -static int swap_pager_almost_full = 1; /* swap space exhaustion (w/hysteresis)*/ +static bool swap_pager_full = true; /* swap space exhaustion (task killing) */ +static bool swap_pager_almost_full = true; /* swap space exhaustion (w/hysteresis) */ static struct mtx swbuf_mtx; /* to sync nsw_wcount_async */ static int nsw_wcount_async; /* limit async write buffers */ static int nsw_wcount_async_max;/* assigned maximum */ @@ -642,14 +642,14 @@ swp_sizecheck(void) { if (swap_pager_avail < nswap_lowat) { - if (swap_pager_almost_full == 0) { + if (!swap_pager_almost_full) { printf("swap_pager: out of swap space\n"); - swap_pager_almost_full = 1; + swap_pager_almost_full = true; } } else { - swap_pager_full = 0; + swap_pager_full = false; if (swap_pager_avail > nswap_hiwat) - swap_pager_almost_full = 0; + swap_pager_almost_full = false; } } @@ -958,11 +958,10 @@ swp_pager_getswapspace(int *io_npages) swp_sizecheck(); swdevhd = TAILQ_NEXT(sp, sw_list); } else { - if (swap_pager_full != 2) { + if (!swap_pager_full) { printf("swp_pager_getswapspace(%d): failed\n", *io_npages); - swap_pager_full = 2; - swap_pager_almost_full = 1; + swap_pager_full = swap_pager_almost_full = true; } swdevhd = NULL; } @@ -2863,10 +2862,8 @@ swapoff_one(struct swdevt *sp, struct ucred *cred, u_int flags) sp->sw_id = NULL; TAILQ_REMOVE(&swtailq, sp, sw_list); nswapdev--; - if (nswapdev == 0) { - swap_pager_full = 2; - swap_pager_almost_full = 1; - } + if (nswapdev == 0) + swap_pager_full = swap_pager_almost_full = true; if (swdevhd == sp) swdevhd = NULL; mtx_unlock(&sw_dev_mtx); diff --git a/sys/vm/vm_domainset.c b/sys/vm/vm_domainset.c index 7b8bf4c77663..b44bdb96b0d4 100644 --- a/sys/vm/vm_domainset.c +++ b/sys/vm/vm_domainset.c @@ -131,8 +131,7 @@ static void vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain) { - KASSERT(di->di_n > 0, - ("vm_domainset_iter_first: Invalid n %d", di->di_n)); + KASSERT(di->di_n > 0, ("%s: Invalid n %d", __func__, di->di_n)); switch (di->di_policy) { case DOMAINSET_POLICY_FIRSTTOUCH: /* @@ -149,11 +148,10 @@ vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain) vm_domainset_iter_prefer(di, domain); break; default: - panic("vm_domainset_iter_first: Unknown policy %d", - di->di_policy); + panic("%s: Unknown policy %d", __func__, di->di_policy); } KASSERT(*domain < vm_ndomains, - ("vm_domainset_iter_next: Invalid domain %d", *domain)); + ("%s: Invalid domain %d", __func__, *domain)); } static void @@ -189,13 +187,11 @@ vm_domainset_iter_first(struct vm_domainset_iter *di, int *domain) di->di_n = di->di_domain->ds_cnt; break; default: - panic("vm_domainset_iter_first: Unknown policy %d", - di->di_policy); + panic("%s: Unknown policy %d", __func__, di->di_policy); } - KASSERT(di->di_n > 0, - ("vm_domainset_iter_first: Invalid n %d", di->di_n)); + KASSERT(di->di_n > 0, ("%s: Invalid n %d", __func__, di->di_n)); KASSERT(*domain < vm_ndomains, - ("vm_domainset_iter_first: Invalid domain %d", *domain)); + ("%s: Invalid domain %d", __func__, *domain)); } void diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 21584abacfa3..3e57e8d4f1d0 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1441,8 +1441,7 @@ vm_fault_busy_sleep(struct faultstate *fs) } vm_object_pip_wakeup(fs->object); vm_fault_unlock_map(fs); - if (fs->m != vm_page_lookup(fs->object, fs->pindex) || - !vm_page_busy_sleep(fs->m, "vmpfw", 0)) + if (!vm_page_busy_sleep(fs->m, "vmpfw", 0)) VM_OBJECT_UNLOCK(fs->object); VM_CNT_INC(v_intrans); vm_object_deallocate(fs->first_object); diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 875c22d27628..e7d7b6726d2c 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -110,11 +110,18 @@ u_int exec_map_entry_size; u_int exec_map_entries; SYSCTL_ULONG(_vm, OID_AUTO, min_kernel_address, CTLFLAG_RD, - SYSCTL_NULL_ULONG_PTR, VM_MIN_KERNEL_ADDRESS, "Min kernel address"); +#if defined(__amd64__) + &kva_layout.km_low, 0, +#else + SYSCTL_NULL_ULONG_PTR, VM_MIN_KERNEL_ADDRESS, +#endif + "Min kernel address"); SYSCTL_ULONG(_vm, OID_AUTO, max_kernel_address, CTLFLAG_RD, #if defined(__arm__) &vm_max_kernel_address, 0, +#elif defined(__amd64__) + &kva_layout.km_high, 0, #else SYSCTL_NULL_ULONG_PTR, VM_MAX_KERNEL_ADDRESS, #endif diff --git a/sys/vm/vm_pagequeue.h b/sys/vm/vm_pagequeue.h index cbbd27389662..9bd3b389fb60 100644 --- a/sys/vm/vm_pagequeue.h +++ b/sys/vm/vm_pagequeue.h @@ -260,9 +260,9 @@ struct vm_domain { u_int vmd_inactive_shortage; /* Per-thread shortage. */ blockcount_t vmd_inactive_running; /* Number of inactive threads. */ blockcount_t vmd_inactive_starting; /* Number of threads started. */ - volatile u_int vmd_addl_shortage; /* Shortage accumulator. */ - volatile u_int vmd_inactive_freed; /* Successful inactive frees. */ - volatile u_int vmd_inactive_us; /* Microseconds for above. */ + u_int vmd_addl_shortage; /* (a) Shortage accumulator. */ + u_int vmd_inactive_freed; /* (a) Successful inactive frees. */ + u_int vmd_inactive_us; /* (a) Microseconds for above. */ u_int vmd_inactive_pps; /* Exponential decay frees/second. */ int vmd_oom_seq; int vmd_last_active_scan; |