diff options
author | attilio <attilio@FreeBSD.org> | 2013-03-02 14:48:41 +0000 |
---|---|---|
committer | attilio <attilio@FreeBSD.org> | 2013-03-02 14:48:41 +0000 |
commit | e98f58faf63a90d85e0e2ad78353915f9615a4eb (patch) | |
tree | b9feaa4bea034f2e9d11c7eb34aa95c672a3a86b /sys | |
parent | bcc31f462ba76b89e3789cb24393126466e3775d (diff) | |
parent | 5d33901b24a0ca4496b12ca2299df4b62dfdfd35 (diff) | |
download | FreeBSD-src-e98f58faf63a90d85e0e2ad78353915f9615a4eb.zip FreeBSD-src-e98f58faf63a90d85e0e2ad78353915f9615a4eb.tar.gz |
MFC
Diffstat (limited to 'sys')
160 files changed, 3962 insertions, 1921 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 046c7a1..f5e1437 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -659,7 +659,7 @@ cpu_halt(void) halt(); } -void (*cpu_idle_hook)(void) = NULL; /* ACPI idle hook. */ +void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */ static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ TUNABLE_INT("machdep.idle_mwait", &idle_mwait); @@ -671,7 +671,7 @@ SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, #define STATE_SLEEPING 0x2 static void -cpu_idle_acpi(int busy) +cpu_idle_acpi(sbintime_t sbt) { int *state; @@ -683,14 +683,14 @@ cpu_idle_acpi(int busy) if (sched_runnable()) enable_intr(); else if (cpu_idle_hook) - cpu_idle_hook(); + cpu_idle_hook(sbt); else __asm __volatile("sti; hlt"); *state = STATE_RUNNING; } static void -cpu_idle_hlt(int busy) +cpu_idle_hlt(sbintime_t sbt) { int *state; @@ -731,7 +731,7 @@ cpu_idle_hlt(int busy) #define MWAIT_C4 0x30 static void -cpu_idle_mwait(int busy) +cpu_idle_mwait(sbintime_t sbt) { int *state; @@ -754,7 +754,7 @@ cpu_idle_mwait(int busy) } static void -cpu_idle_spin(int busy) +cpu_idle_spin(sbintime_t sbt) { int *state; int i; @@ -803,12 +803,13 @@ cpu_probe_amdc1e(void) } } -void (*cpu_idle_fn)(int) = cpu_idle_acpi; +void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi; void cpu_idle(int busy) { uint64_t msr; + sbintime_t sbt = -1; CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", busy, curcpu); @@ -826,7 +827,7 @@ cpu_idle(int busy) /* If we have time - switch timers into idle mode. */ if (!busy) { critical_enter(); - cpu_idleclock(); + sbt = cpu_idleclock(); } /* Apply AMD APIC timer C1E workaround. */ @@ -837,7 +838,7 @@ cpu_idle(int busy) } /* Call main idle method. */ - cpu_idle_fn(busy); + cpu_idle_fn(sbt); /* Switch timers mack into active mode. */ if (!busy) { diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 7d63f0c..10481a7 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -2222,7 +2222,7 @@ reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp) if ((tpte & PG_A) != 0) vm_page_aflag_set(m, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); if (TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); @@ -2506,9 +2506,9 @@ pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va) pv_entry_t pv; rw_assert(&pvh_global_lock, RA_LOCKED); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (pmap == PV_PMAP(pv) && va == pv->pv_va) { - TAILQ_REMOVE(&pvh->pv_list, pv, pv_list); + TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); break; } } @@ -2547,7 +2547,7 @@ pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, pv = pmap_pvh_remove(pvh, pmap, va); KASSERT(pv != NULL, ("pmap_pv_demote_pde: pv not found")); m = PHYS_TO_VM_PAGE(pa); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); /* Instantiate the remaining NPTEPG - 1 pv entries. */ PV_STAT(atomic_add_long(&pv_entry_allocs, NPTEPG - 1)); va_last = va + NBPDR - PAGE_SIZE; @@ -2565,7 +2565,7 @@ pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, m++; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_pv_demote_pde: page %p is not managed", m)); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); if (va == va_last) goto out; } @@ -2613,7 +2613,7 @@ pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, pv = pmap_pvh_remove(&m->md, pmap, va); KASSERT(pv != NULL, ("pmap_pv_promote_pde: pv not found")); pvh = pa_to_pvh(pa); - TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); /* Free the remaining NPTEPG - 1 pv entries. */ va_last = va + NBPDR - PAGE_SIZE; do { @@ -2654,7 +2654,7 @@ pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m, if ((pv = get_pv_entry(pmap, NULL)) != NULL) { pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); return (TRUE); } else return (FALSE); @@ -2678,7 +2678,7 @@ pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); pvh = pa_to_pvh(pa); - TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); return (TRUE); } else return (FALSE); @@ -3157,7 +3157,7 @@ small_mappings: vm_page_dirty(m); pmap_unuse_pt(pmap, pv->pv_va, *pde, &free); pmap_invalidate_page(pmap, pv->pv_va); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } @@ -3602,7 +3602,7 @@ retry: pv = get_pv_entry(pmap, &lock); pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, pa); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); if ((newpte & PG_RW) != 0) vm_page_aflag_set(m, PGA_WRITEABLE); } @@ -4295,7 +4295,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; @@ -4306,7 +4306,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) } if (!rv && loops < 16 && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; @@ -4358,7 +4358,7 @@ pmap_pvh_wired_mappings(struct md_page *pvh, int count) pv_entry_t pv; rw_assert(&pvh_global_lock, RA_WLOCKED); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte(pmap, pv->pv_va); @@ -4489,7 +4489,7 @@ pmap_remove_pages(pmap_t pmap) if ((tpte & PG_PS) != 0) { pmap_resident_count_dec(pmap, NBPDR / PAGE_SIZE); pvh = pa_to_pvh(tpte & PG_PS_FRAME); - TAILQ_REMOVE(&pvh->pv_list, pv, pv_list); + TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); if (TAILQ_EMPTY(&pvh->pv_list)) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) if ((mt->aflags & PGA_WRITEABLE) != 0 && @@ -4508,7 +4508,7 @@ pmap_remove_pages(pmap_t pmap) } } else { pmap_resident_count_dec(pmap, 1); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); if ((m->aflags & PGA_WRITEABLE) != 0 && TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { @@ -4583,7 +4583,7 @@ pmap_is_modified_pvh(struct md_page *pvh) rw_assert(&pvh_global_lock, RA_WLOCKED); rv = FALSE; - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte(pmap, pv->pv_va); @@ -4654,7 +4654,7 @@ pmap_is_referenced_pvh(struct md_page *pvh) rw_assert(&pvh_global_lock, RA_WLOCKED); rv = FALSE; - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte(pmap, pv->pv_va); @@ -4695,7 +4695,7 @@ pmap_remove_write(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); va = pv->pv_va; @@ -4705,7 +4705,7 @@ pmap_remove_write(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4758,7 +4758,7 @@ pmap_ts_referenced(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, pvn) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, pvn) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); va = pv->pv_va; @@ -4792,9 +4792,9 @@ small_mappings: if ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { pvf = pv; do { - pvn = TAILQ_NEXT(pv, pv_list); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + pvn = TAILQ_NEXT(pv, pv_next); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4846,7 +4846,7 @@ pmap_clear_modify(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); va = pv->pv_va; @@ -4878,7 +4878,7 @@ pmap_clear_modify(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4915,7 +4915,7 @@ pmap_clear_reference(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); va = pv->pv_va; @@ -4938,7 +4938,7 @@ pmap_clear_reference(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 5819a0d..3988195 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -138,7 +138,7 @@ device sa # Sequential Access (tape etc) device cd # CD device pass # Passthrough device (direct ATA/SCSI access) device ses # Enclosure Services (SES and SAF-TE) -device ctl # CAM Target Layer +#device ctl # CAM Target Layer # RAID controllers interfaced to the SCSI subsystem device amr # AMI MegaRAID diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h index 334d6c6..0fc8867 100644 --- a/sys/amd64/include/pmap.h +++ b/sys/amd64/include/pmap.h @@ -277,7 +277,7 @@ extern struct pmap kernel_pmap_store; */ typedef struct pv_entry { vm_offset_t pv_va; /* virtual address for mapping */ - TAILQ_ENTRY(pv_entry) pv_list; + TAILQ_ENTRY(pv_entry) pv_next; } *pv_entry_t; /* diff --git a/sys/arm/allwinner/files.a10 b/sys/arm/allwinner/files.a10 index 9e947de..c25682a 100644 --- a/sys/arm/allwinner/files.a10 +++ b/sys/arm/allwinner/files.a10 @@ -17,5 +17,5 @@ arm/allwinner/timer.c standard arm/allwinner/aintc.c standard arm/allwinner/bus_space.c standard arm/allwinner/common.c standard -arm/allwinner/console.c standard +#arm/allwinner/console.c standard arm/allwinner/a10_machdep.c standard diff --git a/sys/arm/allwinner/timer.c b/sys/arm/allwinner/timer.c index 4da3517..49c5f18 100644 --- a/sys/arm/allwinner/timer.c +++ b/sys/arm/allwinner/timer.c @@ -95,7 +95,7 @@ int a10_timer_get_timerfreq(struct a10_timer_softc *); static u_int a10_timer_get_timecount(struct timecounter *); static int a10_timer_timer_start(struct eventtimer *, - struct bintime *, struct bintime *); + sbintime_t first, sbintime_t period); static int a10_timer_timer_stop(struct eventtimer *); static uint64_t timer_read_counter64(void); @@ -193,12 +193,8 @@ a10_timer_attach(device_t dev) sc->et.et_name = "a10_timer Eventtimer"; sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; sc->et.et_quality = 1000; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = - ((0x00000005LLU << 32) / sc->et.et_frequency) << 32; - sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency; + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = a10_timer_timer_start; sc->et.et_stop = a10_timer_timer_stop; sc->et.et_priv = sc; @@ -225,8 +221,8 @@ a10_timer_attach(device_t dev) } static int -a10_timer_timer_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +a10_timer_timer_start(struct eventtimer *et, sbintime_t first, + sbintime_t period) { struct a10_timer_softc *sc; uint32_t count; @@ -234,26 +230,21 @@ a10_timer_timer_start(struct eventtimer *et, struct bintime *first, sc = (struct a10_timer_softc *)et->et_priv; - sc->sc_period = 0; - - if (period != NULL) { - sc->sc_period = (sc->et.et_frequency * (period->frac >> 32)) >> 32; - sc->sc_period += sc->et.et_frequency * period->sec; - } - if (first == NULL) + if (period != 0) + sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32; + else + sc->sc_period = 0; + if (first != 0) + count = ((uint32_t)et->et_frequency * first) >> 32; + else count = sc->sc_period; - else { - count = (sc->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - count += sc->et.et_frequency * first->sec; - } /* Update timer values */ timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, sc->sc_period); timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, count); val = timer_read_4(sc, SW_TIMER0_CTRL_REG); - if (first == NULL) { + if (period != 0) { /* periodic */ val |= TIMER_AUTORELOAD; } else { diff --git a/sys/arm/arm/locore.S b/sys/arm/arm/locore.S index 00a61e7..37e88fe 100644 --- a/sys/arm/arm/locore.S +++ b/sys/arm/arm/locore.S @@ -204,6 +204,7 @@ mmu_done: virt_done: mov r1, #20 /* loader info size is 20 bytes also second arg */ subs sp, sp, r1 /* allocate arm_boot_params struct on stack */ + bic sp, sp, #7 /* align stack to 8 bytes */ mov r0, sp /* loader info pointer is first arg */ str r1, [r0] /* Store length of loader info */ str r9, [r0, #4] /* Store r0 from boot loader */ diff --git a/sys/arm/arm/mpcore_timer.c b/sys/arm/arm/mpcore_timer.c index 41a0b27..8445d3d 100644 --- a/sys/arm/arm/mpcore_timer.c +++ b/sys/arm/arm/mpcore_timer.c @@ -167,31 +167,23 @@ arm_tmr_get_timecount(struct timecounter *tc) * Always returns 0 */ static int -arm_tmr_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { - struct arm_tmr_softc *sc = (struct arm_tmr_softc *)et->et_priv; uint32_t load, count; uint32_t ctrl; ctrl = PRV_TIMER_CTRL_IRQ_ENABLE | PRV_TIMER_CTRL_TIMER_ENABLE; - if (period != NULL) { - load = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec > 0) - load += et->et_frequency * period->sec; + if (period != 0) { + load = ((uint32_t)et->et_frequency * period) >> 32; ctrl |= PRV_TIMER_CTRL_AUTO_RELOAD; - } else { + } else load = 0; - } - if (first != NULL) { - count = (sc->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - count += sc->et.et_frequency * first->sec; - } else { + if (first != 0) + count = ((uint32_t)et->et_frequency * first) >> 32; + else count = load; - } tmr_prv_write_4(PRV_TIMER_LOAD, load); tmr_prv_write_4(PRV_TIMER_COUNT, count); @@ -330,12 +322,8 @@ arm_tmr_attach(device_t dev) sc->et.et_quality = 1000; sc->et.et_frequency = sc->clkfreq; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = - ((0x00000002LLU << 32) / sc->et.et_frequency) << 32; - sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = arm_tmr_start; sc->et.et_stop = arm_tmr_stop; sc->et.et_priv = sc; diff --git a/sys/arm/broadcom/bcm2835/bcm2835_dma.c b/sys/arm/broadcom/bcm2835/bcm2835_dma.c new file mode 100644 index 0000000..5e1c9dc --- /dev/null +++ b/sys/arm/broadcom/bcm2835/bcm2835_dma.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2013 Daisuke Aoyama <aoyama@peach.ne.jp> + * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@bluezbox.com> + * + * 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/queue.h> +#include <sys/resource.h> +#include <sys/rman.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/pmap.h> + +#include "bcm2835_dma.h" +#include "bcm2835_vcbus.h" + +#define MAX_REG 9 + +/* private flags */ +#define BCM_DMA_CH_USED 0x00000001 +#define BCM_DMA_CH_FREE 0x40000000 +#define BCM_DMA_CH_UNMAP 0x80000000 + +/* Register Map (4.2.1.2) */ +#define BCM_DMA_CS(n) (0x100*(n) + 0x00) +#define CS_ACTIVE (1 << 0) +#define CS_END (1 << 1) +#define CS_INT (1 << 2) +#define CS_DREQ (1 << 3) +#define CS_ISPAUSED (1 << 4) +#define CS_ISHELD (1 << 5) +#define CS_ISWAIT (1 << 6) +#define CS_ERR (1 << 8) +#define CS_WAITWRT (1 << 28) +#define CS_DISDBG (1 << 29) +#define CS_ABORT (1 << 30) +#define CS_RESET (1 << 31) +#define BCM_DMA_CBADDR(n) (0x100*(n) + 0x04) +#define BCM_DMA_INFO(n) (0x100*(n) + 0x08) +#define INFO_INT_EN (1 << 0) +#define INFO_TDMODE (1 << 1) +#define INFO_WAIT_RESP (1 << 3) +#define INFO_D_INC (1 << 4) +#define INFO_D_WIDTH (1 << 5) +#define INFO_D_DREQ (1 << 6) +#define INFO_S_INC (1 << 8) +#define INFO_S_WIDTH (1 << 9) +#define INFO_S_DREQ (1 << 10) +#define INFO_WAITS_SHIFT (21) +#define INFO_PERMAP_SHIFT (16) +#define INFO_PERMAP_MASK (0x1f << INFO_PERMAP_SHIFT) + +#define BCM_DMA_SRC(n) (0x100*(n) + 0x0C) +#define BCM_DMA_DST(n) (0x100*(n) + 0x10) +#define BCM_DMA_LEN(n) (0x100*(n) + 0x14) +#define BCM_DMA_STRIDE(n) (0x100*(n) + 0x18) +#define BCM_DMA_CBNEXT(n) (0x100*(n) + 0x1C) +#define BCM_DMA_DEBUG(n) (0x100*(n) + 0x20) +#define DEBUG_ERROR_MASK (7) + +#define BCM_DMA_INT_STATUS 0xfe0 +#define BCM_DMA_ENABLE 0xff0 + +/* relative offset from BCM_VC_DMA0_BASE (p.39) */ +#define BCM_DMA_CH(n) (0x100*(n)) + +/* DMA Control Block - 256bit aligned (p.40) */ +struct bcm_dma_cb { + uint32_t info; /* Transfer Information */ + uint32_t src; /* Source Address */ + uint32_t dst; /* Destination Address */ + uint32_t len; /* Transfer Length */ + uint32_t stride; /* 2D Mode Stride */ + uint32_t next; /* Next Control Block Address */ + uint32_t rsvd1; /* Reserved */ + uint32_t rsvd2; /* Reserved */ +}; + +#ifdef DEBUG +static void bcm_dma_cb_dump(struct bcm_dma_cb *cb); +static void bcm_dma_reg_dump(int ch); +#endif + +/* DMA channel private info */ +struct bcm_dma_ch { + int ch; + uint32_t flags; + struct bcm_dma_cb * cb; + uint32_t vc_cb; + bus_dmamap_t dma_map; + void (*intr_func)(int, void *); + void * intr_arg; +}; + +struct bcm_dma_softc { + device_t sc_dev; + struct mtx sc_mtx; + struct resource * sc_mem; + struct resource * sc_irq[BCM_DMA_CH_MAX]; + void * sc_intrhand[BCM_DMA_CH_MAX]; + struct bcm_dma_ch sc_dma_ch[BCM_DMA_CH_MAX]; + bus_dma_tag_t sc_dma_tag; +}; + +static struct bcm_dma_softc *bcm_dma_sc = NULL; + +static void +bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs, + int nseg, int err) +{ + bus_addr_t *addr; + + if (err) + return; + + addr = (bus_addr_t*)arg; + *addr = PHYS_TO_VCBUS(segs[0].ds_addr); +} + +static void +bcm_dma_reset(device_t dev, int ch) +{ + struct bcm_dma_softc *sc = device_get_softc(dev); + struct bcm_dma_cb *cb; + uint32_t cs; + int count; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return; + + cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); + + if (cs & CS_ACTIVE) { + /* pause current task */ + bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), 0); + + count = 1000; + do { + cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); + } while (!(cs & CS_ISPAUSED) && (count-- > 0)); + + if (!(cs & CS_ISPAUSED)) { + device_printf(dev, + "Can't abort DMA transfer at channel %d\n", ch); + } + + bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); + + /* Complete everything, clear interrupt */ + bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), + CS_ABORT | CS_INT | CS_END| CS_ACTIVE); + } + + /* clear control blocks */ + bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), 0); + bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); + + /* Reset control block */ + cb = sc->sc_dma_ch[ch].cb; + bzero(cb, sizeof(cb)); +} + +static int +bcm_dma_init(device_t dev) +{ + struct bcm_dma_softc *sc = device_get_softc(dev); + uint32_t mask; + struct bcm_dma_ch *ch; + void *cb_virt; + vm_paddr_t cb_phys; + int err; + int i; + + /* disable and clear interrupt status */ + bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, 0); + bus_write_4(sc->sc_mem, BCM_DMA_INT_STATUS, 0); + + /* Allocate DMA chunks control blocks */ + /* p.40 of spec - control block should be 32-bit aligned */ + err = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, + sizeof(struct bcm_dma_cb), 1, + sizeof(struct bcm_dma_cb), + BUS_DMA_ALLOCNOW, NULL, NULL, + &sc->sc_dma_tag); + + if (err) { + device_printf(dev, "failed allocate DMA tag"); + return (err); + } + + /* setup initial settings */ + for (i = 0; i < BCM_DMA_CH_MAX; i++) { + ch = &sc->sc_dma_ch[i]; + + err = bus_dmamem_alloc(sc->sc_dma_tag, &cb_virt, + BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, + &ch->dma_map); + if (err) { + device_printf(dev, "cannot allocate DMA memory\n"); + break; + } + + /* + * Least alignment for busdma-allocated stuff is cache + * line size, so just make sure nothing stupid happend + * and we got properly aligned address + */ + if ((uintptr_t)cb_virt & 0x1f) { + device_printf(dev, + "DMA address is not 32-bytes aligned: %p\n", + (void*)cb_virt); + break; + } + + err = bus_dmamap_load(sc->sc_dma_tag, ch->dma_map, cb_virt, + sizeof(struct bcm_dma_cb), bcm_dmamap_cb, &cb_phys, + BUS_DMA_WAITOK); + if (err) { + device_printf(dev, "cannot load DMA memory\n"); + break; + } + + bzero(ch, sizeof(struct bcm_dma_ch)); + ch->ch = i; + ch->cb = cb_virt; + ch->vc_cb = cb_phys; + ch->intr_func = NULL; + ch->intr_arg = NULL; + ch->flags = BCM_DMA_CH_UNMAP; + + ch->cb->info = INFO_WAIT_RESP; + + /* reset DMA engine */ + bcm_dma_reset(dev, i); + } + + /* now use DMA2/DMA3 only */ + sc->sc_dma_ch[2].flags = BCM_DMA_CH_FREE; + sc->sc_dma_ch[3].flags = BCM_DMA_CH_FREE; + + /* enable DMAs */ + mask = 0; + + for (i = 0; i < BCM_DMA_CH_MAX; i++) + if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) + mask |= (1 << i); + + bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, mask); + + return (0); +} + +/* + * Allocate DMA channel for further use, returns channel # or + * BCM_DMA_CH_INVALID + */ +int +bcm_dma_allocate(int req_ch) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + int ch = BCM_DMA_CH_INVALID; + int i; + + if (req_ch >= BCM_DMA_CH_MAX) + return (BCM_DMA_CH_INVALID); + + /* Auto(req_ch < 0) or CH specified */ + mtx_lock(&sc->sc_mtx); + + if (req_ch < 0) { + for (i = 0; i < BCM_DMA_CH_MAX; i++) { + if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) { + ch = i; + sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; + sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; + break; + } + } + } + else { + if (sc->sc_dma_ch[req_ch].flags & BCM_DMA_CH_FREE) { + ch = req_ch; + sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; + sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; + } + } + + mtx_unlock(&sc->sc_mtx); + return (ch); +} + +/* + * Frees allocated channel. Returns 0 on success, -1 otherwise + */ +int +bcm_dma_free(int ch) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (-1); + + mtx_lock(&sc->sc_mtx); + if (sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED) { + sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_FREE; + sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_USED; + sc->sc_dma_ch[ch].intr_func = NULL; + sc->sc_dma_ch[ch].intr_arg = NULL; + + /* reset DMA engine */ + bcm_dma_reset(sc->sc_dev, ch); + } + + mtx_unlock(&sc->sc_mtx); + return (0); +} + +/* + * Assign handler function for channel interrupt + * Returns 0 on success, -1 otherwise + */ +int +bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + struct bcm_dma_cb *cb; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (-1); + + if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) + return (-1); + + sc->sc_dma_ch[ch].intr_func = func; + sc->sc_dma_ch[ch].intr_arg = arg; + cb = sc->sc_dma_ch[ch].cb; + cb->info |= INFO_INT_EN; + + return (0); +} + +/* + * Setup DMA source parameters + * ch - channel number + * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if + * source is physical memory + * inc_addr - BCM_DMA_INC_ADDR if source address + * should be increased after each access or + * BCM_DMA_SAME_ADDR if address should remain + * the same + * width - size of read operation, BCM_DMA_32BIT + * for 32bit bursts, BCM_DMA_128BIT for 128 bits + * + * Returns 0 on success, -1 otherwise + */ +int +bcm_dma_setup_src(int ch, int dreq, int inc_addr, int width) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + uint32_t info; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (-1); + + if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) + return (-1); + + info = sc->sc_dma_ch[ch].cb->info; + info &= ~INFO_PERMAP_MASK; + info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; + + if (dreq) + info |= INFO_S_DREQ; + else + info &= ~INFO_S_DREQ; + + if (width == BCM_DMA_128BIT) + info |= INFO_S_WIDTH; + else + info &= ~INFO_S_WIDTH; + + if (inc_addr == BCM_DMA_INC_ADDR) + info |= INFO_S_INC; + else + info &= ~INFO_S_INC; + + sc->sc_dma_ch[ch].cb->info = info; + + return (0); +} + +/* + * Setup DMA destination parameters + * ch - channel number + * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if + * destination is physical memory + * inc_addr - BCM_DMA_INC_ADDR if source address + * should be increased after each access or + * BCM_DMA_SAME_ADDR if address should remain + * the same + * width - size of write operation, BCM_DMA_32BIT + * for 32bit bursts, BCM_DMA_128BIT for 128 bits + * + * Returns 0 on success, -1 otherwise + */ +int +bcm_dma_setup_dst(int ch, int dreq, int inc_addr, int width) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + uint32_t info; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (-1); + + if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) + return (-1); + + info = sc->sc_dma_ch[ch].cb->info; + info &= ~INFO_PERMAP_MASK; + info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; + + if (dreq) + info |= INFO_D_DREQ; + else + info &= ~INFO_D_DREQ; + + if (width == BCM_DMA_128BIT) + info |= INFO_D_WIDTH; + else + info &= ~INFO_D_WIDTH; + + if (inc_addr == BCM_DMA_INC_ADDR) + info |= INFO_D_INC; + else + info &= ~INFO_D_INC; + + sc->sc_dma_ch[ch].cb->info = info; + + return (0); +} + +#ifdef DEBUG +void +bcm_dma_cb_dump(struct bcm_dma_cb *cb) +{ + + printf("DMA CB "); + printf("INFO: %8.8x ", cb->info); + printf("SRC: %8.8x ", cb->src); + printf("DST: %8.8x ", cb->dst); + printf("LEN: %8.8x ", cb->len); + printf("\n"); + printf("STRIDE: %8.8x ", cb->stride); + printf("NEXT: %8.8x ", cb->next); + printf("RSVD1: %8.8x ", cb->rsvd1); + printf("RSVD2: %8.8x ", cb->rsvd2); + printf("\n"); +} + +void +bcm_dma_reg_dump(int ch) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + int i; + uint32_t reg; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return; + + printf("DMA%d: ", ch); + for (i = 0; i < MAX_REG; i++) { + reg = bus_read_4(sc->sc_mem, BCM_DMA_CH(ch) + i*4); + printf("%8.8x ", reg); + } + printf("\n"); +} +#endif + +/* + * Start DMA transaction + * ch - channel number + * src, dst - source and destination address in + * ARM physical memory address space. + * len - amount of bytes to be transfered + * + * Returns 0 on success, -1 otherwise + */ +int +bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + struct bcm_dma_cb *cb; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (-1); + + if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) + return (-1); + + cb = sc->sc_dma_ch[ch].cb; + if (BCM2835_ARM_IS_IO(src)) + cb->src = IO_TO_VCBUS(src); + else + cb->src = PHYS_TO_VCBUS(src); + if (BCM2835_ARM_IS_IO(dst)) + cb->dst = IO_TO_VCBUS(dst); + else + cb->dst = PHYS_TO_VCBUS(dst); + cb->len = len; + + bus_dmamap_sync(sc->sc_dma_tag, + sc->sc_dma_ch[ch].dma_map, BUS_DMASYNC_PREWRITE); + + bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), + sc->sc_dma_ch[ch].vc_cb); + bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), CS_ACTIVE); + +#ifdef DEBUG + bcm_dma_cb_dump(sc->sc_dma_ch[ch].cb); + bcm_dma_reg_dump(ch); +#endif + + return (0); +} + +/* + * Get length requested for DMA transaction + * ch - channel number + * + * Returns size of transaction, 0 if channel is invalid + */ +uint32_t +bcm_dma_length(int ch) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + struct bcm_dma_cb *cb; + + if (ch < 0 || ch >= BCM_DMA_CH_MAX) + return (0); + + if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) + return (0); + + cb = sc->sc_dma_ch[ch].cb; + + return (cb->len); +} + +static void +bcm_dma_intr(void *arg) +{ + struct bcm_dma_softc *sc = bcm_dma_sc; + struct bcm_dma_ch *ch = (struct bcm_dma_ch *)arg; + uint32_t cs, debug; + + /* my interrupt? */ + cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch->ch)); + + if (!(cs & (CS_INT | CS_ERR))) + return; + + /* running? */ + if (!(ch->flags & BCM_DMA_CH_USED)) { + device_printf(sc->sc_dev, + "unused DMA intr CH=%d, CS=%x\n", ch->ch, cs); + return; + } + + if (cs & CS_ERR) { + debug = bus_read_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch)); + device_printf(sc->sc_dev, "DMA error %d on CH%d\n", + debug & DEBUG_ERROR_MASK, ch->ch); + bus_write_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch), + debug & DEBUG_ERROR_MASK); + } + + if (cs & CS_INT) { + /* acknowledge interrupt */ + bus_write_4(sc->sc_mem, BCM_DMA_CS(ch->ch), + CS_INT | CS_END); + + /* Prepare for possible access to len field */ + bus_dmamap_sync(sc->sc_dma_tag, ch->dma_map, + BUS_DMASYNC_POSTWRITE); + + /* save callback function and argument */ + if (ch->intr_func) + ch->intr_func(ch->ch, ch->intr_arg); + } +} + +static int +bcm_dma_probe(device_t dev) +{ + + if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-dma")) + return (ENXIO); + + device_set_desc(dev, "BCM2835 DMA Controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +bcm_dma_attach(device_t dev) +{ + struct bcm_dma_softc *sc = device_get_softc(dev); + int rid, err = 0; + int i; + + sc->sc_dev = dev; + + if (bcm_dma_sc) + return (ENXIO); + + for (i = 0; i < BCM_DMA_CH_MAX; i++) { + sc->sc_irq[i] = NULL; + sc->sc_intrhand[i] = NULL; + } + + /* DMA0 - DMA14 */ + rid = 0; + sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->sc_mem == NULL) { + device_printf(dev, "could not allocate memory resource\n"); + return (ENXIO); + } + + /* IRQ DMA0 - DMA11 XXX NOT USE DMA12(spurious?) */ + for (rid = 0; rid < BCM_DMA_CH_MAX; rid++) { + sc->sc_irq[rid] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->sc_irq[rid] == NULL) { + device_printf(dev, "cannot allocate interrupt\n"); + err = ENXIO; + goto fail; + } + if (bus_setup_intr(dev, sc->sc_irq[rid], INTR_TYPE_MISC | INTR_MPSAFE, + NULL, bcm_dma_intr, &sc->sc_dma_ch[rid], + &sc->sc_intrhand[rid])) { + device_printf(dev, "cannot setup interrupt handler\n"); + err = ENXIO; + goto fail; + } + } + + mtx_init(&sc->sc_mtx, "bcmdma", "bcmdma", MTX_DEF); + bcm_dma_sc = sc; + + err = bcm_dma_init(dev); + if (err) + goto fail; + + return (err); + +fail: + if (sc->sc_mem) + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem); + + for (i = 0; i < BCM_DMA_CH_MAX; i++) { + if (sc->sc_intrhand[i]) + bus_teardown_intr(dev, sc->sc_irq[i], sc->sc_intrhand[i]); + if (sc->sc_irq[i]) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq[i]); + } + + return (err); +} + +static device_method_t bcm_dma_methods[] = { + DEVMETHOD(device_probe, bcm_dma_probe), + DEVMETHOD(device_attach, bcm_dma_attach), + { 0, 0 } +}; + +static driver_t bcm_dma_driver = { + "bcm_dma", + bcm_dma_methods, + sizeof(struct bcm_dma_softc), +}; + +static devclass_t bcm_dma_devclass; + +DRIVER_MODULE(bcm_dma, simplebus, bcm_dma_driver, bcm_dma_devclass, 0, 0); +MODULE_VERSION(bcm_dma, 1); diff --git a/sys/arm/broadcom/bcm2835/bcm2835_dma.h b/sys/arm/broadcom/bcm2835/bcm2835_dma.h new file mode 100644 index 0000000..785cf2c --- /dev/null +++ b/sys/arm/broadcom/bcm2835/bcm2835_dma.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Daisuke Aoyama <aoyama@peach.ne.jp> + * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@bluezbox.com> + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _BCM2835_DMA_H_ +#define _BCM2835_DMA_H_ + +#define BCM_DMA_BLOCK_SIZE 512 + +/* DMA0-DMA15 but DMA15 is special */ +#define BCM_DMA_CH_MAX 12 + +/* request CH for any nubmer */ +#define BCM_DMA_CH_INVALID (-1) +#define BCM_DMA_CH_ANY (-1) +#define BCM_DMA_CH_FAST1 (2) +#define BCM_DMA_CH_FAST2 (3) + +/* Peripheral DREQ Signals (4.2.1.3) */ +#define BCM_DMA_DREQ_NONE 0 +#define BCM_DMA_DREQ_EMMC 11 +#define BCM_DMA_DREQ_SDHOST 13 + +#define BCM_DMA_SAME_ADDR 0 +#define BCM_DMA_INC_ADDR 1 + +#define BCM_DMA_32BIT 0 +#define BCM_DMA_128BIT 1 + +int bcm_dma_allocate(int req_ch); +int bcm_dma_free(int ch); +int bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg); +int bcm_dma_setup_src(int ch, int dreq, int inc_addr, int width); +int bcm_dma_setup_dst(int ch, int dreq, int inc_addr, int width); +int bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len); +uint32_t bcm_dma_length(int ch); + +#endif /* _BCM2835_DMA_H_ */ diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index cfba2cd..3512954 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -67,8 +67,13 @@ __FBSDID("$FreeBSD$"); #include <dev/sdhci/sdhci.h> #include "sdhci_if.h" +#include "bcm2835_dma.h" +#include "bcm2835_vcbus.h" + #define BCM2835_DEFAULT_SDHCI_FREQ 50 +#define BCM_SDHCI_BUFFER_SIZE 512 + #define DEBUG #ifdef DEBUG @@ -85,9 +90,11 @@ __FBSDID("$FreeBSD$"); */ static int bcm2835_sdhci_min_freq = 400000; static int bcm2835_sdhci_hs = 1; +static int bcm2835_sdhci_pio_mode = 0; TUNABLE_INT("hw.bcm2835.sdhci.min_freq", &bcm2835_sdhci_min_freq); TUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs); +TUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode); struct bcm_sdhci_dmamap_arg { bus_addr_t sc_dma_busaddr; @@ -111,23 +118,41 @@ struct bcm_sdhci_softc { int sc_xfer_done; int sc_bus_busy; struct sdhci_slot sc_slot; + int sc_dma_inuse; + int sc_dma_ch; + bus_dma_tag_t sc_dma_tag; + bus_dmamap_t sc_dma_map; + void *sc_dma_buffer; + vm_paddr_t sc_dma_buffer_phys; + vm_paddr_t sc_sdhci_buffer_phys;; }; -#define SD_MAX_BLOCKSIZE 1024 -/* XXX */ - static int bcm_sdhci_probe(device_t); static int bcm_sdhci_attach(device_t); static int bcm_sdhci_detach(device_t); static void bcm_sdhci_intr(void *); static int bcm_sdhci_get_ro(device_t, device_t); +static void bcm_sdhci_dma_intr(int ch, void *arg); #define bcm_sdhci_lock(_sc) \ mtx_lock(&_sc->sc_mtx); #define bcm_sdhci_unlock(_sc) \ mtx_unlock(&_sc->sc_mtx); +static void +bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs, + int nseg, int err) +{ + bus_addr_t *addr; + + if (err) + return; + + addr = (bus_addr_t*)arg; + *addr = segs[0].ds_addr; +} + static int bcm_sdhci_probe(device_t dev) { @@ -146,9 +171,13 @@ bcm_sdhci_attach(device_t dev) phandle_t node; pcell_t cell; int default_freq; + void *buffer; + vm_paddr_t buffer_phys; + void *va; sc->sc_dev = dev; sc->sc_req = NULL; + err = 0; default_freq = BCM2835_DEFAULT_SDHCI_FREQ; node = ofw_bus_get_node(sc->sc_dev); @@ -191,6 +220,9 @@ bcm_sdhci_attach(device_t dev) goto fail; } + if (!bcm2835_sdhci_pio_mode) + sc->sc_slot.opt = SDHCI_PLATFORM_TRANSFER; + sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180; if (bcm2835_sdhci_hs) sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD; @@ -201,6 +233,61 @@ bcm_sdhci_attach(device_t dev) sdhci_init_slot(dev, &sc->sc_slot, 0); + sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST1); + if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) + sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST2); + if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) + sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY); + if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) + goto fail; + + bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc); + + /* Allocate DMA buffers */ + err = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, + BCM_SDHCI_BUFFER_SIZE, 1, BCM_SDHCI_BUFFER_SIZE, + BUS_DMA_ALLOCNOW, NULL, NULL, + &sc->sc_dma_tag); + + if (err) { + device_printf(dev, "failed allocate DMA tag"); + goto fail; + } + + err = bus_dmamem_alloc(sc->sc_dma_tag, &buffer, + BUS_DMA_WAITOK | BUS_DMA_COHERENT| BUS_DMA_ZERO, + &sc->sc_dma_map); + + if (err) { + device_printf(dev, "cannot allocate DMA memory\n"); + goto fail; + } + + err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, buffer, + BCM_SDHCI_BUFFER_SIZE, bcm_dmamap_cb, &buffer_phys, + BUS_DMA_WAITOK); + if (err) { + device_printf(dev, "cannot load DMA memory\n"); + goto fail; + } + + /* + * Sanity check: two least bits of address should be zero + */ + if ((uintptr_t)buffer & 3) { + device_printf(dev, + "DMA address is not word-aligned\n"); + goto fail; + } + + sc->sc_dma_buffer = buffer; + sc->sc_dma_buffer_phys = buffer_phys; + va = (void*)rman_get_start(sc->sc_mem_res); + sc->sc_sdhci_buffer_phys = + pmap_kextract((vm_offset_t)va) + SDHCI_BUFFER; + bus_generic_probe(dev); bus_generic_attach(dev); @@ -354,6 +441,211 @@ bcm_sdhci_min_freq(device_t dev, struct sdhci_slot *slot) return bcm2835_sdhci_min_freq; } +static void +bcm_sdhci_dma_intr(int ch, void *arg) +{ + struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg; + struct sdhci_slot *slot = &sc->sc_slot; + uint32_t reg, mask; + void *buffer; + size_t len; + int left; + + mtx_lock(&slot->mtx); + + /* copy DMA buffer to VA if READ */ + len = bcm_dma_length(sc->sc_dma_ch); + if (slot->curcmd->data->flags & MMC_DATA_READ) { + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTREAD); + + mask = SDHCI_INT_DATA_AVAIL; + /* all dma data in single or contiguous page */ + buffer = (uint8_t*)(slot->curcmd->data->data) + slot->offset; + memcpy(buffer, sc->sc_dma_buffer, len); + } else { + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTWRITE); + mask = SDHCI_INT_SPACE_AVAIL; + } + + slot->offset += len; + sc->sc_dma_inuse = 0; + + left = min(BCM_SDHCI_BUFFER_SIZE, + slot->curcmd->data->len - slot->offset); + + /* DATA END? */ + reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS); + + if (reg & SDHCI_INT_DATA_END) { + /* ACK for all outstanding interrupts */ + bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg); + + /* enable INT */ + slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL + | SDHCI_INT_DATA_END; + bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, + slot->intmask); + + /* finish this data */ + sdhci_finish_data(slot); + } + else { + /* already available? */ + if (reg & mask) { + sc->sc_dma_inuse = 1; + + /* ACK for DATA_AVAIL or SPACE_AVAIL */ + bcm_sdhci_write_4(slot->bus, slot, + SDHCI_INT_STATUS, mask); + + /* continue next DMA transfer */ + if (slot->curcmd->data->flags & MMC_DATA_READ) { + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_PREREAD); + + /* DMA start */ + if (bcm_dma_start(sc->sc_dma_ch, + sc->sc_sdhci_buffer_phys, + sc->sc_dma_buffer_phys, left) != 0) + device_printf(sc->sc_dev, "failed DMA start\n"); + } else { + buffer = (char*)slot->curcmd->data->data + slot->offset; + memcpy(sc->sc_dma_buffer, buffer, left); + + bus_dmamap_sync(sc->sc_dma_tag, + sc->sc_dma_map, BUS_DMASYNC_PREWRITE); + + /* DMA start */ + if (bcm_dma_start(sc->sc_dma_ch, + sc->sc_dma_buffer_phys, + sc->sc_sdhci_buffer_phys, left) != 0) + device_printf(sc->sc_dev, "failed DMA start\n"); + } + } else { + /* wait for next data by INT */ + + /* enable INT */ + slot->intmask |= SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END; + bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, + slot->intmask); + } + } + + mtx_unlock(&slot->mtx); +} + +static void +bcm_sdhci_read_dma(struct sdhci_slot *slot) +{ + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); + size_t left; + + if (sc->sc_dma_inuse) { + device_printf(sc->sc_dev, "DMA in use\n"); + return; + } + + sc->sc_dma_inuse = 1; + + left = min(BCM_SDHCI_BUFFER_SIZE, + slot->curcmd->data->len - slot->offset); + + KASSERT((left & 3) == 0, + ("%s: len = %d, not word-aligned", __func__, left)); + + bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, + BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); + bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, + BCM_DMA_INC_ADDR, + (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); + + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_PREREAD); + + /* DMA start */ + if (bcm_dma_start(sc->sc_dma_ch, sc->sc_sdhci_buffer_phys, + sc->sc_dma_buffer_phys, left) != 0) + device_printf(sc->sc_dev, "failed DMA start\n"); +} + +static void +bcm_sdhci_write_dma(struct sdhci_slot *slot) +{ + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); + char *buffer; + size_t left; + + if (sc->sc_dma_inuse) { + device_printf(sc->sc_dev, "DMA in use\n"); + return; + } + + sc->sc_dma_inuse = 1; + + left = min(BCM_SDHCI_BUFFER_SIZE, + slot->curcmd->data->len - slot->offset); + + KASSERT((left & 3) == 0, + ("%s: len = %d, not word-aligned", __func__, left)); + + buffer = (char*)slot->curcmd->data->data + slot->offset; + memcpy(sc->sc_dma_buffer, buffer, left); + + bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, + BCM_DMA_INC_ADDR, + (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); + bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, + BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); + + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_PREWRITE); + + /* DMA start */ + if (bcm_dma_start(sc->sc_dma_ch, sc->sc_dma_buffer_phys, + sc->sc_sdhci_buffer_phys, left) != 0) + device_printf(sc->sc_dev, "failed DMA start\n"); +} + +static int +bcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot) +{ + size_t left; + + /* Do not use DMA for transfers less then block size */ + left = min(BCM_DMA_BLOCK_SIZE, + slot->curcmd->data->len - slot->offset); + if (left < BCM_DMA_BLOCK_SIZE) + return (0); + + return (1); +} + +static void +bcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot, + uint32_t *intmask) +{ + + /* Disable INT */ + slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END); + bcm_sdhci_write_4(dev, slot, SDHCI_SIGNAL_ENABLE, slot->intmask); + + /* DMA transfer FIFO 1KB */ + if (slot->curcmd->data->flags & MMC_DATA_READ) + bcm_sdhci_read_dma(slot); + else + bcm_sdhci_write_dma(slot); +} + +static void +bcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot) +{ + + sdhci_finish_data(slot); +} + static device_method_t bcm_sdhci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bcm_sdhci_probe), @@ -372,8 +664,12 @@ static device_method_t bcm_sdhci_methods[] = { DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), - /* SDHCI registers accessors */ DEVMETHOD(sdhci_min_freq, bcm_sdhci_min_freq), + /* Platform transfer methods */ + DEVMETHOD(sdhci_platform_will_handle, bcm_sdhci_will_handle_transfer), + DEVMETHOD(sdhci_platform_start_transfer, bcm_sdhci_start_transfer), + DEVMETHOD(sdhci_platform_finish_transfer, bcm_sdhci_finish_transfer), + /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, bcm_sdhci_read_1), DEVMETHOD(sdhci_read_2, bcm_sdhci_read_2), DEVMETHOD(sdhci_read_4, bcm_sdhci_read_4), diff --git a/sys/arm/broadcom/bcm2835/bcm2835_systimer.c b/sys/arm/broadcom/bcm2835/bcm2835_systimer.c index 97ec43a..1d7fdda 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_systimer.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_systimer.c @@ -118,19 +118,16 @@ bcm_systimer_tc_get_timecount(struct timecounter *tc) } static int -bcm_systimer_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +bcm_systimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct systimer *st = et->et_priv; uint32_t clo; uint32_t count; register_t s; - if (first != NULL) { + if (first != 0) { - count = (st->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - count += st->et.et_frequency * first->sec; + count = ((uint32_t)et->et_frequency * first) >> 32; s = intr_disable(); clo = bcm_systimer_tc_read_4(SYSTIMER_CLO); @@ -238,12 +235,10 @@ bcm_systimer_attach(device_t dev) sc->st[DEFAULT_TIMER].et.et_flags = ET_FLAGS_ONESHOT; sc->st[DEFAULT_TIMER].et.et_quality = 1000; sc->st[DEFAULT_TIMER].et.et_frequency = sc->sysclk_freq; - sc->st[DEFAULT_TIMER].et.et_min_period.sec = 0; - sc->st[DEFAULT_TIMER].et.et_min_period.frac = - ((MIN_PERIOD << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32; - sc->st[DEFAULT_TIMER].et.et_max_period.sec = 0xfffffff0U / sc->st[DEFAULT_TIMER].et.et_frequency; - sc->st[DEFAULT_TIMER].et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32; + sc->st[DEFAULT_TIMER].et.et_min_period = + (MIN_PERIOD << 32) / sc->st[DEFAULT_TIMER].et.et_frequency; + sc->st[DEFAULT_TIMER].et.et_max_period = + (0xfffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency; sc->st[DEFAULT_TIMER].et.et_start = bcm_systimer_start; sc->st[DEFAULT_TIMER].et.et_stop = bcm_systimer_stop; sc->st[DEFAULT_TIMER].et.et_priv = &sc->st[DEFAULT_TIMER]; diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 9885155..aa1af40 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -1,5 +1,6 @@ # $FreeBSD$ +arm/broadcom/bcm2835/bcm2835_dma.c standard arm/broadcom/bcm2835/bcm2835_fb.c optional sc arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio arm/broadcom/bcm2835/bcm2835_intr.c standard diff --git a/sys/arm/conf/CUBIEBOARD b/sys/arm/conf/CUBIEBOARD index fa5bfc8..1c0407b 100644 --- a/sys/arm/conf/CUBIEBOARD +++ b/sys/arm/conf/CUBIEBOARD @@ -87,8 +87,8 @@ options ROOTDEVNAME=\"ufs:/dev/da0s2\" #options ATA_STATIC_ID # Static device numbering # Console and misc -#device uart -#device uart_ns8250 +device uart +device uart_ns8250 device pty device snp device md diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index d9e8d38..4d840cb 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -117,4 +117,4 @@ options FDT # Note: DTB is normally loaded and modified by RPi boot loader, then # handed to kernel via U-Boot and ubldr. #options FDT_DTB_STATIC -#makeoptions FDT_DTS_FILE=bcm2835-rpi-b.dts +makeoptions FDT_DTS_FILE=bcm2835-rpi-b.dts diff --git a/sys/arm/econa/econa_machdep.c b/sys/arm/econa/econa_machdep.c index d622860..d64e826 100644 --- a/sys/arm/econa/econa_machdep.c +++ b/sys/arm/econa/econa_machdep.c @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/include/vmparam.h b/sys/arm/include/vmparam.h index 09bf62c..9765b34 100644 --- a/sys/arm/include/vmparam.h +++ b/sys/arm/include/vmparam.h @@ -34,9 +34,32 @@ #ifndef _MACHINE_VMPARAM_H_ #define _MACHINE_VMPARAM_H_ +/* + * Machine dependent constants for ARM. + */ + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (64UL*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (128UL*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (512UL*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (2UL*1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ (8UL*1024*1024) /* max stack size */ +#endif +#ifndef SGROWSIZ +#define SGROWSIZ (128UL*1024) /* amount to grow stack */ +#endif -/*#include <arm/arm32/vmparam.h> -*/ /* * Address space constants */ @@ -153,23 +176,6 @@ VM_MIN_KERNEL_ADDRESS + 1) * 2 / 5) #endif -#define MAXTSIZ (16*1024*1024) -#ifndef DFLDSIZ -#define DFLDSIZ (128*1024*1024) -#endif -#ifndef MAXDSIZ -#define MAXDSIZ (512*1024*1024) -#endif -#ifndef DFLSSIZ -#define DFLSSIZ (2*1024*1024) -#endif -#ifndef MAXSSIZ -#define MAXSSIZ (8*1024*1024) -#endif -#ifndef SGROWSIZ -#define SGROWSIZ (128*1024) -#endif - #ifdef ARM_USE_SMALL_ALLOC #define UMA_MD_SMALL_ALLOC #endif /* ARM_USE_SMALL_ALLOC */ @@ -178,4 +184,8 @@ extern vm_offset_t vm_max_kernel_address; #define ZERO_REGION_SIZE (64 * 1024) /* 64KB */ +#ifndef VM_MAX_AUTOTUNE_MAXUSERS +#define VM_MAX_AUTOTUNE_MAXUSERS 384 +#endif + #endif /* _MACHINE_VMPARAM_H_ */ diff --git a/sys/arm/lpc/lpc_timer.c b/sys/arm/lpc/lpc_timer.c index 87ed104..8572e1a 100644 --- a/sys/arm/lpc/lpc_timer.c +++ b/sys/arm/lpc/lpc_timer.c @@ -72,8 +72,8 @@ static struct lpc_timer_softc *timer_softc = NULL; static int lpc_timer_initialized = 0; static int lpc_timer_probe(device_t); static int lpc_timer_attach(device_t); -static int lpc_timer_start(struct eventtimer *, struct bintime *first, - struct bintime *); +static int lpc_timer_start(struct eventtimer *, + sbintime_t first, sbintime_t period); static int lpc_timer_stop(struct eventtimer *et); static unsigned lpc_get_timecount(struct timecounter *); static int lpc_hardclock(void *); @@ -173,12 +173,8 @@ lpc_timer_attach(device_t dev) sc->lt_et.et_name = "LPC32x0 Timer0"; sc->lt_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; sc->lt_et.et_quality = 1000; - sc->lt_et.et_min_period.sec = 0; - sc->lt_et.et_min_period.frac = - ((0x00000002LLU << 32) / sc->lt_et.et_frequency) << 32; - sc->lt_et.et_max_period.sec = 0xfffffff0U / sc->lt_et.et_frequency; - sc->lt_et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->lt_et.et_frequency) << 32; + sc->lt_et.et_min_period = (0x00000002LLU << 32) / sc->lt_et.et_frequency; + sc->lt_et.et_max_period = (0xfffffffeLLU << 32) / sc->lt_et.et_frequency; sc->lt_et.et_start = lpc_timer_start; sc->lt_et.et_stop = lpc_timer_stop; sc->lt_et.et_priv = sc; @@ -199,27 +195,23 @@ lpc_timer_attach(device_t dev) } static int -lpc_timer_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +lpc_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct lpc_timer_softc *sc = (struct lpc_timer_softc *)et->et_priv; uint32_t ticks; - if (period == NULL) + if (period == 0) { sc->lt_oneshot = 1; - else { + sc->lt_period = 0; + } else { sc->lt_oneshot = 0; - sc->lt_period = (sc->lt_et.et_frequency * (first->frac >> 32)) >> 32; - sc->lt_period += sc->lt_et.et_frequency * first->sec; + sc->lt_period = ((uint32_t)et->et_frequency * period) >> 32; } - if (first == NULL) + if (first == 0) ticks = sc->lt_period; - else { - ticks = (sc->lt_et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - ticks += sc->lt_et.et_frequency * first->sec; - } + else + ticks = ((uint32_t)et->et_frequency * first) >> 32; /* Reset timer */ timer0_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_RESET); diff --git a/sys/arm/mv/timer.c b/sys/arm/mv/timer.c index db6e404..51a6c17 100644 --- a/sys/arm/mv/timer.c +++ b/sys/arm/mv/timer.c @@ -93,7 +93,7 @@ static void mv_watchdog_enable(void); static void mv_watchdog_disable(void); static void mv_watchdog_event(void *, unsigned int, int *); static int mv_timer_start(struct eventtimer *et, - struct bintime *first, struct bintime *period); + sbintime_t first, sbintime_t period); static int mv_timer_stop(struct eventtimer *et); static void mv_setup_timers(void); @@ -168,12 +168,8 @@ mv_timer_attach(device_t dev) sc->et.et_quality = 1000; sc->et.et_frequency = MV_CLOCK_SRC; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = - ((0x00000002LLU << 32) / sc->et.et_frequency) << 32; - sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = mv_timer_start; sc->et.et_stop = mv_timer_stop; sc->et.et_priv = sc; @@ -394,25 +390,20 @@ mv_watchdog_event(void *arg, unsigned int cmd, int *error) } static int -mv_timer_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +mv_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct mv_timer_softc *sc; uint32_t val, val1; /* Calculate dividers. */ sc = (struct mv_timer_softc *)et->et_priv; - if (period != NULL) { - val = (sc->et.et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - val += sc->et.et_frequency * period->sec; - } else + if (period != 0) + val = ((uint32_t)sc->et.et_frequency * period) >> 32; + else val = 0; - if (first != NULL) { - val1 = (sc->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - val1 += sc->et.et_frequency * first->sec; - } else + if (first != 0) + val1 = ((uint32_t)sc->et.et_frequency * first) >> 32; + else val1 = val; /* Apply configuration. */ @@ -420,7 +411,7 @@ mv_timer_start(struct eventtimer *et, mv_set_timer(0, val1); val = mv_get_timer_control(); val |= CPU_TIMER0_EN; - if (period != NULL) + if (period != 0) val |= CPU_TIMER0_AUTO; else val &= ~CPU_TIMER0_AUTO; diff --git a/sys/arm/s3c2xx0/s3c24x0_machdep.c b/sys/arm/s3c2xx0/s3c24x0_machdep.c index e497bc4..1811b52 100644 --- a/sys/arm/s3c2xx0/s3c24x0_machdep.c +++ b/sys/arm/s3c2xx0/s3c24x0_machdep.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/ti/am335x/am335x_dmtimer.c b/sys/arm/ti/am335x/am335x_dmtimer.c index be9832c..93911f2 100644 --- a/sys/arm/ti/am335x/am335x_dmtimer.c +++ b/sys/arm/ti/am335x/am335x_dmtimer.c @@ -143,30 +143,24 @@ am335x_dmtimer_tc_get_timecount(struct timecounter *tc) } static int -am335x_dmtimer_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +am335x_dmtimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv; uint32_t load, count; uint32_t tclr = 0; - if (period != NULL) { - load = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec > 0) - load += et->et_frequency * period->sec; + if (period != 0) { + load = ((uint32_t)et->et_frequency * period) >> 32; tclr |= 2; /* autoreload bit */ panic("periodic timer not implemented\n"); } else { load = 0; } - if (first != NULL) { - count = (tmr->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - count += tmr->et.et_frequency * first->sec; - } else { + if (first != 0) + count = ((uint32_t)et->et_frequency * first) >> 32; + else count = load; - } /* Reset Timer */ am335x_dmtimer_et_write_4(DMTIMER_TSICR, 2); @@ -316,12 +310,10 @@ am335x_dmtimer_attach(device_t dev) sc->t[3].et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; sc->t[3].et.et_quality = 1000; sc->t[3].et.et_frequency = sc->sysclk_freq; - sc->t[3].et.et_min_period.sec = 0; - sc->t[3].et.et_min_period.frac = - ((0x00000002LLU << 32) / sc->t[3].et.et_frequency) << 32; - sc->t[3].et.et_max_period.sec = 0xfffffff0U / sc->t[3].et.et_frequency; - sc->t[3].et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->t[3].et.et_frequency) << 32; + sc->t[3].et.et_min_period = + (0x00000002LLU << 32) / sc->t[3].et.et_frequency; + sc->t[3].et.et_max_period = + (0xfffffffeLLU << 32) / sc->t[3].et.et_frequency; sc->t[3].et.et_start = am335x_dmtimer_start; sc->t[3].et.et_stop = am335x_dmtimer_stop; sc->t[3].et.et_priv = &sc->t[3]; diff --git a/sys/arm/versatile/sp804.c b/sys/arm/versatile/sp804.c index 82a1889..000ccb6 100644 --- a/sys/arm/versatile/sp804.c +++ b/sys/arm/versatile/sp804.c @@ -120,18 +120,15 @@ sp804_timer_tc_get_timecount(struct timecounter *tc) } static int -sp804_timer_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +sp804_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct sp804_timer_softc *sc = et->et_priv; uint32_t count, reg; - if (first != NULL) { + if (first != 0) { sc->et_enabled = 1; - count = (sc->et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - count += sc->et.et_frequency * first->sec; + count = ((uint32_t)et->et_frequency * first) >> 32; sp804_timer_tc_write_4(SP804_TIMER2_LOAD, count); reg = TIMER_CONTROL_32BIT | TIMER_CONTROL_INTREN | @@ -142,7 +139,7 @@ sp804_timer_start(struct eventtimer *et, struct bintime *first, return (0); } - if (period != NULL) { + if (period != 0) { panic("period"); } @@ -264,12 +261,8 @@ sp804_timer_attach(device_t dev) sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; sc->et.et_quality = 1000; sc->et.et_frequency = sc->sysclk_freq / DEFAULT_DIVISOR; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = - ((0x00000002LLU << 32) / sc->et.et_frequency) << 32; - sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = sp804_timer_start; sc->et.et_stop = sp804_timer_stop; sc->et.et_priv = sc; diff --git a/sys/arm/xscale/i80321/ep80219_machdep.c b/sys/arm/xscale/i80321/ep80219_machdep.c index cb3d161..ff2f1c3 100644 --- a/sys/arm/xscale/i80321/ep80219_machdep.c +++ b/sys/arm/xscale/i80321/ep80219_machdep.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/xscale/i80321/iq31244_machdep.c b/sys/arm/xscale/i80321/iq31244_machdep.c index 2375b6b..1412635 100644 --- a/sys/arm/xscale/i80321/iq31244_machdep.c +++ b/sys/arm/xscale/i80321/iq31244_machdep.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c index a1344af..4ae836b 100644 --- a/sys/arm/xscale/i8134x/crb_machdep.c +++ b/sys/arm/xscale/i8134x/crb_machdep.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c index 07026da..82e1aab0 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/arm/xscale/pxa/pxa_machdep.c b/sys/arm/xscale/pxa/pxa_machdep.c index 706fb58..5640622 100644 --- a/sys/arm/xscale/pxa/pxa_machdep.c +++ b/sys/arm/xscale/pxa/pxa_machdep.c @@ -80,7 +80,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> -#include <machine/pmap.h> #include <machine/vmparam.h> #include <machine/pcb.h> #include <machine/undefined.h> diff --git a/sys/boot/fdt/dts/cubieboard.dts b/sys/boot/fdt/dts/cubieboard.dts index abb3f45..181d5d4 100644 --- a/sys/boot/fdt/dts/cubieboard.dts +++ b/sys/boot/fdt/dts/cubieboard.dts @@ -121,6 +121,8 @@ interrupt-parent = <&AINTC>; current-speed = <115200>; clock-frequency = < 24000000 >; + busy-detect = <1>; + broken-txfifo = <1>; }; }; diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h index d227981..9d71fa2 100644 --- a/sys/bsm/audit_kevents.h +++ b/sys/bsm/audit_kevents.h @@ -588,7 +588,7 @@ #define AUE_OPENAT 43184 /* FreeBSD. */ #define AUE_POSIX_OPENPT 43185 /* FreeBSD. */ #define AUE_CAP_NEW 43186 /* TrustedBSD. */ -#define AUE_CAP_GETRIGHTS 43187 /* TrustedBSD. */ +#define AUE_CAP_RIGHTS_GET 43187 /* TrustedBSD. */ #define AUE_CAP_ENTER 43188 /* TrustedBSD. */ #define AUE_CAP_GETMODE 43189 /* TrustedBSD. */ #define AUE_POSIX_SPAWN 43190 /* Darwin. */ @@ -603,6 +603,11 @@ #define AUE_PDGETPID 43199 /* FreeBSD. */ #define AUE_PDWAIT 43200 /* FreeBSD. */ #define AUE_WAIT6 43201 /* FreeBSD. */ +#define AUE_CAP_RIGHTS_LIMIT 43202 /* TrustedBSD. */ +#define AUE_CAP_IOCTLS_LIMIT 43203 /* TrustedBSD. */ +#define AUE_CAP_IOCTLS_GET 43204 /* TrustedBSD. */ +#define AUE_CAP_FCNTLS_LIMIT 43205 /* TrustedBSD. */ +#define AUE_CAP_FCNTLS_GET 43206 /* TrustedBSD. */ /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the diff --git a/sys/cddl/compat/opensolaris/sys/file.h b/sys/cddl/compat/opensolaris/sys/file.h index 7a3df36..0b8f875 100644 --- a/sys/cddl/compat/opensolaris/sys/file.h +++ b/sys/cddl/compat/opensolaris/sys/file.h @@ -39,15 +39,11 @@ typedef struct file file_t; #include <sys/capability.h> static __inline file_t * -getf(int fd) +getf(int fd, cap_rights_t rights) { struct file *fp; - /* - * We wouldn't need all of these rights on every invocation - * if we had more information about intent. - */ - if (fget(curthread, fd, CAP_READ | CAP_WRITE | CAP_SEEK, &fp) == 0) + if (fget(curthread, fd, rights, &fp) == 0) return (fp); return (NULL); } diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c index 0b43c78..4959335 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Martin Matuska <mm@FreeBSD.org>. All rights reserved. + * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. * Portions Copyright 2005, 2010, Oracle and/or its affiliates. * All rights reserved. * Use is subject to license terms. @@ -35,22 +35,100 @@ #include <sys/zfs_ioctl.h> #include "zfs_ioctl_compat.h" +static int zfs_version_ioctl = ZFS_IOCVER_CURRENT; +SYSCTL_DECL(_vfs_zfs_version); +SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl, + 0, "ZFS_IOCTL_VERSION"); + /* - * FreeBSD zfs_cmd compatibility with v15 and older binaries + * FreeBSD zfs_cmd compatibility with older binaries * appropriately remap/extend the zfs_cmd_t structure */ void zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) { zfs_cmd_v15_t *zc_c; + zfs_cmd_v28_t *zc28_c; - if (cflag == ZFS_CMD_COMPAT_V15) { + switch (cflag) { + case ZFS_CMD_COMPAT_V28: + zc28_c = (void *)addr; + + /* zc */ + strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN); + strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2); + strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN); + strlcpy(zc->zc_top_ds, zc28_c->zc_top_ds, MAXPATHLEN); + zc->zc_guid = zc28_c->zc_guid; + zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf; + zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size; + zc->zc_nvlist_src = zc28_c->zc_nvlist_src; + zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size; + zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst; + zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size; + zc->zc_cookie = zc28_c->zc_cookie; + zc->zc_objset_type = zc28_c->zc_objset_type; + zc->zc_perm_action = zc28_c->zc_perm_action; + zc->zc_history = zc28_c->zc_history; + zc->zc_history_len = zc28_c->zc_history_len; + zc->zc_history_offset = zc28_c->zc_history_offset; + zc->zc_obj = zc28_c->zc_obj; + zc->zc_iflags = zc28_c->zc_iflags; + zc->zc_share = zc28_c->zc_share; + zc->zc_jailid = zc28_c->zc_jailid; + zc->zc_objset_stats = zc28_c->zc_objset_stats; + zc->zc_begin_record = zc28_c->zc_begin_record; + zc->zc_defer_destroy = zc28_c->zc_defer_destroy; + zc->zc_temphold = zc28_c->zc_temphold; + zc->zc_action_handle = zc28_c->zc_action_handle; + zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd; + zc->zc_simple = zc28_c->zc_simple; + bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); + zc->zc_sendobj = zc28_c->zc_sendobj; + zc->zc_fromobj = zc28_c->zc_fromobj; + zc->zc_createtxg = zc28_c->zc_createtxg; + zc->zc_stat = zc28_c->zc_stat; + + /* zc->zc_inject_record */ + zc->zc_inject_record.zi_objset = + zc28_c->zc_inject_record.zi_objset; + zc->zc_inject_record.zi_object = + zc28_c->zc_inject_record.zi_object; + zc->zc_inject_record.zi_start = + zc28_c->zc_inject_record.zi_start; + zc->zc_inject_record.zi_end = + zc28_c->zc_inject_record.zi_end; + zc->zc_inject_record.zi_guid = + zc28_c->zc_inject_record.zi_guid; + zc->zc_inject_record.zi_level = + zc28_c->zc_inject_record.zi_level; + zc->zc_inject_record.zi_error = + zc28_c->zc_inject_record.zi_error; + zc->zc_inject_record.zi_type = + zc28_c->zc_inject_record.zi_type; + zc->zc_inject_record.zi_freq = + zc28_c->zc_inject_record.zi_freq; + zc->zc_inject_record.zi_failfast = + zc28_c->zc_inject_record.zi_failfast; + strlcpy(zc->zc_inject_record.zi_func, + zc28_c->zc_inject_record.zi_func, MAXNAMELEN); + zc->zc_inject_record.zi_iotype = + zc28_c->zc_inject_record.zi_iotype; + zc->zc_inject_record.zi_duration = + zc28_c->zc_inject_record.zi_duration; + zc->zc_inject_record.zi_timer = + zc28_c->zc_inject_record.zi_timer; + zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED; + zc->zc_inject_record.zi_pad = 0; + break; + + case ZFS_CMD_COMPAT_V15: zc_c = (void *)addr; /* zc */ - strlcpy(zc->zc_name,zc_c->zc_name,MAXPATHLEN); - strlcpy(zc->zc_value,zc_c->zc_value,MAXPATHLEN); - strlcpy(zc->zc_string,zc_c->zc_string,MAXPATHLEN); + strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN); + strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN); + strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN); zc->zc_guid = zc_c->zc_guid; zc->zc_nvlist_conf = zc_c->zc_nvlist_conf; zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size; @@ -91,6 +169,7 @@ zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) zc_c->zc_inject_record.zi_freq; zc->zc_inject_record.zi_failfast = zc_c->zc_inject_record.zi_failfast; + break; } } @@ -98,15 +177,84 @@ void zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int cflag) { zfs_cmd_v15_t *zc_c; + zfs_cmd_v28_t *zc28_c; switch (cflag) { + case ZFS_CMD_COMPAT_V28: + zc28_c = (void *)addr; + + strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN); + strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2); + strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN); + strlcpy(zc28_c->zc_top_ds, zc->zc_top_ds, MAXPATHLEN); + zc28_c->zc_guid = zc->zc_guid; + zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf; + zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; + zc28_c->zc_nvlist_src = zc->zc_nvlist_src; + zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; + zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst; + zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; + zc28_c->zc_cookie = zc->zc_cookie; + zc28_c->zc_objset_type = zc->zc_objset_type; + zc28_c->zc_perm_action = zc->zc_perm_action; + zc28_c->zc_history = zc->zc_history; + zc28_c->zc_history_len = zc->zc_history_len; + zc28_c->zc_history_offset = zc->zc_history_offset; + zc28_c->zc_obj = zc->zc_obj; + zc28_c->zc_iflags = zc->zc_iflags; + zc28_c->zc_share = zc->zc_share; + zc28_c->zc_jailid = zc->zc_jailid; + zc28_c->zc_objset_stats = zc->zc_objset_stats; + zc28_c->zc_begin_record = zc->zc_begin_record; + zc28_c->zc_defer_destroy = zc->zc_defer_destroy; + zc28_c->zc_temphold = zc->zc_temphold; + zc28_c->zc_action_handle = zc->zc_action_handle; + zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd; + zc28_c->zc_simple = zc->zc_simple; + bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad)); + zc28_c->zc_sendobj = zc->zc_sendobj; + zc28_c->zc_fromobj = zc->zc_fromobj; + zc28_c->zc_createtxg = zc->zc_createtxg; + zc28_c->zc_stat = zc->zc_stat; + + /* zc_inject_record */ + zc28_c->zc_inject_record.zi_objset = + zc->zc_inject_record.zi_objset; + zc28_c->zc_inject_record.zi_object = + zc->zc_inject_record.zi_object; + zc28_c->zc_inject_record.zi_start = + zc->zc_inject_record.zi_start; + zc28_c->zc_inject_record.zi_end = + zc->zc_inject_record.zi_end; + zc28_c->zc_inject_record.zi_guid = + zc->zc_inject_record.zi_guid; + zc28_c->zc_inject_record.zi_level = + zc->zc_inject_record.zi_level; + zc28_c->zc_inject_record.zi_error = + zc->zc_inject_record.zi_error; + zc28_c->zc_inject_record.zi_type = + zc->zc_inject_record.zi_type; + zc28_c->zc_inject_record.zi_freq = + zc->zc_inject_record.zi_freq; + zc28_c->zc_inject_record.zi_failfast = + zc->zc_inject_record.zi_failfast; + strlcpy(zc28_c->zc_inject_record.zi_func, + zc->zc_inject_record.zi_func, MAXNAMELEN); + zc28_c->zc_inject_record.zi_iotype = + zc->zc_inject_record.zi_iotype; + zc28_c->zc_inject_record.zi_duration = + zc->zc_inject_record.zi_duration; + zc28_c->zc_inject_record.zi_timer = + zc->zc_inject_record.zi_timer; + break; + case ZFS_CMD_COMPAT_V15: zc_c = (void *)addr; /* zc */ - strlcpy(zc_c->zc_name,zc->zc_name,MAXPATHLEN); - strlcpy(zc_c->zc_value,zc->zc_value,MAXPATHLEN); - strlcpy(zc_c->zc_string,zc->zc_string,MAXPATHLEN); + strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN); + strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN); + strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN); zc_c->zc_guid = zc->zc_guid; zc_c->zc_nvlist_conf = zc->zc_nvlist_conf; zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; @@ -260,7 +408,7 @@ zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl) } static int -zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int cflag) +zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc) { nvlist_t *nv, *nvp = NULL; nvpair_t *elem; @@ -270,7 +418,7 @@ zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int cflag) zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) return (error); - if (cflag == 5) { /* ZFS_IOC_POOL_STATS */ + if (nc == 5) { /* ZFS_IOC_POOL_STATS */ elem = NULL; while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) { if (nvpair_value_nvlist(elem, &nvp) == 0) @@ -334,17 +482,22 @@ zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag) void *zc_c; unsigned long ncmd; - if (cflag == ZFS_CMD_COMPAT_NONE) { + switch (cflag) { + case ZFS_CMD_COMPAT_NONE: ret = ioctl(fd, cmd, zc); return (ret); - } - - if (cflag == ZFS_CMD_COMPAT_V15) { + case ZFS_CMD_COMPAT_V28: + zc_c = malloc(sizeof(zfs_cmd_v28_t)); + ncmd = _IOWR('Z', ZFS_IOC(cmd), struct zfs_cmd_v28); + break; + case ZFS_CMD_COMPAT_V15: nc = zfs_ioctl_v28_to_v15[ZFS_IOC(cmd)]; zc_c = malloc(sizeof(zfs_cmd_v15_t)); ncmd = _IOWR('Z', nc, struct zfs_cmd_v15); - } else + break; + default: return (EINVAL); + } if (ZFS_IOC(ncmd) == ZFS_IOC_COMPAT_FAIL) return (ENOTSUP); @@ -358,16 +511,18 @@ zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag) zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag); free(zc_c); - switch (nc) { - case 2: /* ZFS_IOC_POOL_IMPORT */ - case 4: /* ZFS_IOC_POOL_CONFIGS */ - case 5: /* ZFS_IOC_POOL_STATS */ - case 6: /* ZFS_IOC_POOL_TRYIMPORT */ - zfs_ioctl_compat_fix_stats(zc, nc); - break; - case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ - zfs_ioctl_compat_pool_get_props(zc); - break; + if (cflag == ZFS_CMD_COMPAT_V15) { + switch (nc) { + case 2: /* ZFS_IOC_POOL_IMPORT */ + case 4: /* ZFS_IOC_POOL_CONFIGS */ + case 5: /* ZFS_IOC_POOL_STATS */ + case 6: /* ZFS_IOC_POOL_TRYIMPORT */ + zfs_ioctl_compat_fix_stats(zc, nc); + break; + case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ + zfs_ioctl_compat_pool_get_props(zc); + break; + } } return (ret); diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h index 03d648c..b20ceca 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Martin Matuska <mm@FreeBSD.org>. All rights reserved. + * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. * Use is subject to license terms. */ @@ -40,11 +40,21 @@ extern "C" { #endif -#define ZFS_CMD_COMPAT_NONE 0 +/* + * Backwards ioctl compatibility + */ + +/* ioctl versions for vfs.zfs.version.ioctl */ +#define ZFS_IOCVER_DEADMAN 1 +#define ZFS_IOCVER_CURRENT ZFS_IOCVER_DEADMAN + +/* compatibility conversion flag */ +#define ZFS_CMD_COMPAT_NONE 0 #define ZFS_CMD_COMPAT_V15 1 +#define ZFS_CMD_COMPAT_V28 2 -#define ZFS_IOC_COMPAT_PASS 254 -#define ZFS_IOC_COMPAT_FAIL 255 +#define ZFS_IOC_COMPAT_PASS 254 +#define ZFS_IOC_COMPAT_FAIL 255 typedef struct zinject_record_v15 { uint64_t zi_objset; @@ -84,6 +94,60 @@ typedef struct zfs_cmd_v15 { zinject_record_v15_t zc_inject_record; } zfs_cmd_v15_t; +typedef struct zinject_record_v28 { + uint64_t zi_objset; + uint64_t zi_object; + uint64_t zi_start; + uint64_t zi_end; + uint64_t zi_guid; + uint32_t zi_level; + uint32_t zi_error; + uint64_t zi_type; + uint32_t zi_freq; + uint32_t zi_failfast; + char zi_func[MAXNAMELEN]; + uint32_t zi_iotype; + int32_t zi_duration; + uint64_t zi_timer; +} zinject_record_v28_t; + +typedef struct zfs_cmd_v28 { + char zc_name[MAXPATHLEN]; + char zc_value[MAXPATHLEN * 2]; + char zc_string[MAXNAMELEN]; + char zc_top_ds[MAXPATHLEN]; + uint64_t zc_guid; + uint64_t zc_nvlist_conf; /* really (char *) */ + uint64_t zc_nvlist_conf_size; + uint64_t zc_nvlist_src; /* really (char *) */ + uint64_t zc_nvlist_src_size; + uint64_t zc_nvlist_dst; /* really (char *) */ + uint64_t zc_nvlist_dst_size; + uint64_t zc_cookie; + uint64_t zc_objset_type; + uint64_t zc_perm_action; + uint64_t zc_history; /* really (char *) */ + uint64_t zc_history_len; + uint64_t zc_history_offset; + uint64_t zc_obj; + uint64_t zc_iflags; /* internal to zfs(7fs) */ + zfs_share_t zc_share; + uint64_t zc_jailid; + dmu_objset_stats_t zc_objset_stats; + struct drr_begin zc_begin_record; + zinject_record_v28_t zc_inject_record; + boolean_t zc_defer_destroy; + boolean_t zc_temphold; + uint64_t zc_action_handle; + int zc_cleanup_fd; + uint8_t zc_simple; + uint8_t zc_pad[3]; /* alignment */ + uint64_t zc_sendobj; + uint64_t zc_fromobj; + uint64_t zc_createtxg; + zfs_stat_t zc_stat; +} zfs_cmd_v28_t; + #ifdef _KERNEL unsigned static long zfs_ioctl_v15_to_v28[] = { 0, /* 0 ZFS_IOC_POOL_CREATE */ diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c index dc0cb33..4243c20 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. */ @@ -350,6 +350,10 @@ zfs_prop_init(void) ZFS_TYPE_SNAPSHOT, "<count>", "USERREFS"); zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "WRITTEN"); + zprop_register_number(ZFS_PROP_LOGICALUSED, "logicalused", 0, + PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LUSED"); + zprop_register_number(ZFS_PROP_LOGICALREFERENCED, "logicalreferenced", + 0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LREFER"); /* default number properties */ zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT, diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c index e8bf701..b294ff02 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c @@ -2344,6 +2344,8 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) (ds->ds_phys->ds_uncompressed_bytes * 100 / ds->ds_phys->ds_compressed_bytes); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALREFERENCED, + ds->ds_phys->ds_uncompressed_bytes); if (ds->ds_phys->ds_next_snap_obj) { /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c index 4d954bd..79e5121 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c @@ -541,6 +541,8 @@ dsl_dir_stats(dsl_dir_t *dd, nvlist_t *nv) dd->dd_phys->dd_compressed_bytes == 0 ? 100 : (dd->dd_phys->dd_uncompressed_bytes * 100 / dd->dd_phys->dd_compressed_bytes)); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALUSED, + dd->dd_phys->dd_uncompressed_bytes); if (dd->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USEDSNAP, dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c index 92b7e06..ecfc1b0 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c @@ -6018,7 +6018,7 @@ spa_sync_version(void *arg1, void *arg2, dmu_tx_t *tx) */ ASSERT(tx->tx_txg != TXG_INITIAL); - ASSERT(version <= SPA_VERSION); + ASSERT(SPA_VERSION_IS_SUPPORTED(version)); ASSERT(version >= spa_version(spa)); spa->spa_uberblock.ub_version = version; @@ -6559,7 +6559,7 @@ spa_upgrade(spa_t *spa, uint64_t version) * future version would result in an unopenable pool, this shouldn't be * possible. */ - ASSERT(spa->spa_uberblock.ub_version <= SPA_VERSION); + ASSERT(SPA_VERSION_IS_SUPPORTED(spa->spa_uberblock.ub_version)); ASSERT(version >= spa->spa_uberblock.ub_version); spa->spa_uberblock.ub_version = version; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index 9925a3b..fce4bb5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -23,7 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>. * All rights reserved. - * Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org> + * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. @@ -3822,7 +3822,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) return (error); fd = zc->zc_cookie; - fp = getf(fd); + fp = getf(fd, CAP_PREAD); if (fp == NULL) { nvlist_free(props); return (EBADF); @@ -4079,7 +4079,7 @@ zfs_ioc_send(zfs_cmd_t *zc) error = dmu_send_estimate(tosnap, fromsnap, zc->zc_obj, &zc->zc_objset_type); } else { - file_t *fp = getf(zc->zc_cookie); + file_t *fp = getf(zc->zc_cookie, CAP_WRITE); if (fp == NULL) { dsl_dataset_rele(ds, FTAG); if (dsfrom) @@ -4675,7 +4675,7 @@ zfs_ioc_diff(zfs_cmd_t *zc) return (error); } - fp = getf(zc->zc_cookie); + fp = getf(zc->zc_cookie, CAP_WRITE); if (fp == NULL) { dmu_objset_rele(fromsnap, FTAG); dmu_objset_rele(tosnap, FTAG); @@ -5331,12 +5331,14 @@ zfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, len = IOCPARM_LEN(cmd); /* - * Check if we have sufficient kernel memory allocated - * for the zfs_cmd_t request. Bail out if not so we - * will not access undefined memory region. + * Check if we are talking to supported older binaries + * and translate zfs_cmd if necessary */ if (len < sizeof(zfs_cmd_t)) - if (len == sizeof(zfs_cmd_v15_t)) { + if (len == sizeof(zfs_cmd_v28_t)) { + cflag = ZFS_CMD_COMPAT_V28; + vec = ZFS_IOC(cmd); + } else if (len == sizeof(zfs_cmd_v15_t)) { cflag = ZFS_CMD_COMPAT_V15; vec = zfs_ioctl_v15_to_v28[ZFS_IOC(cmd)]; } else @@ -5351,6 +5353,11 @@ zfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, return (ENOTSUP); } + /* + * Check if we have sufficient kernel memory allocated + * for the zfs_cmd_t request. Bail out if not so we + * will not access undefined memory region. + */ if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) return (EINVAL); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c index ca0acfd..c12826f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c @@ -124,7 +124,7 @@ zfs_onexit_fd_hold(int fd, minor_t *minorp) void *data; int error; - fp = getf(fd); + fp = getf(fd, CAP_NONE); if (fp == NULL) return (EBADF); diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h index 64fd2e6..38deab6 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h @@ -131,6 +131,8 @@ typedef enum { ZFS_PROP_REFRATIO, ZFS_PROP_WRITTEN, ZFS_PROP_CLONES, + ZFS_PROP_LOGICALUSED, + ZFS_PROP_LOGICALREFERENCED, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index 2b241df..52156bd 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #ifndef _FREEBSD32_SYSPROTO_H_ diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 76311ba..4b689d3 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #define FREEBSD32_SYS_syscall 0 @@ -416,7 +416,7 @@ #define FREEBSD32_SYS_freebsd32_shmctl 512 #define FREEBSD32_SYS_lpathconf 513 #define FREEBSD32_SYS_cap_new 514 -#define FREEBSD32_SYS_cap_getrights 515 +#define FREEBSD32_SYS_cap_rights_get 515 #define FREEBSD32_SYS_cap_enter 516 #define FREEBSD32_SYS_cap_getmode 517 #define FREEBSD32_SYS_freebsd32_pselect 522 @@ -430,4 +430,9 @@ #define FREEBSD32_SYS_freebsd32_posix_fallocate 530 #define FREEBSD32_SYS_freebsd32_posix_fadvise 531 #define FREEBSD32_SYS_freebsd32_wait6 532 -#define FREEBSD32_SYS_MAXSYSCALL 533 +#define FREEBSD32_SYS_cap_rights_limit 533 +#define FREEBSD32_SYS_cap_ioctls_limit 534 +#define FREEBSD32_SYS_cap_ioctls_get 535 +#define FREEBSD32_SYS_cap_fcntls_limit 536 +#define FREEBSD32_SYS_cap_fcntls_get 537 +#define FREEBSD32_SYS_MAXSYSCALL 538 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index 499b3e8..4878b200 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ const char *freebsd32_syscallnames[] = { @@ -538,7 +538,7 @@ const char *freebsd32_syscallnames[] = { "freebsd32_shmctl", /* 512 = freebsd32_shmctl */ "lpathconf", /* 513 = lpathconf */ "cap_new", /* 514 = cap_new */ - "cap_getrights", /* 515 = cap_getrights */ + "cap_rights_get", /* 515 = cap_rights_get */ "cap_enter", /* 516 = cap_enter */ "cap_getmode", /* 517 = cap_getmode */ "#518", /* 518 = pdfork */ @@ -556,4 +556,9 @@ const char *freebsd32_syscallnames[] = { "freebsd32_posix_fallocate", /* 530 = freebsd32_posix_fallocate */ "freebsd32_posix_fadvise", /* 531 = freebsd32_posix_fadvise */ "freebsd32_wait6", /* 532 = freebsd32_wait6 */ + "cap_rights_limit", /* 533 = cap_rights_limit */ + "cap_ioctls_limit", /* 534 = cap_ioctls_limit */ + "cap_ioctls_get", /* 535 = cap_ioctls_get */ + "cap_fcntls_limit", /* 536 = cap_fcntls_limit */ + "cap_fcntls_get", /* 537 = cap_fcntls_get */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 814d88e..65da2c7 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #include "opt_compat.h" @@ -575,7 +575,7 @@ struct sysent freebsd32_sysent[] = { { AS(freebsd32_shmctl_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 512 = freebsd32_shmctl */ { AS(lpathconf_args), (sy_call_t *)sys_lpathconf, AUE_LPATHCONF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 513 = lpathconf */ { AS(cap_new_args), (sy_call_t *)sys_cap_new, AUE_CAP_NEW, NULL, 0, 0, 0, SY_THR_STATIC }, /* 514 = cap_new */ - { AS(cap_getrights_args), (sy_call_t *)sys_cap_getrights, AUE_CAP_GETRIGHTS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 515 = cap_getrights */ + { AS(cap_rights_get_args), (sy_call_t *)sys_cap_rights_get, AUE_CAP_RIGHTS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 515 = cap_rights_get */ { 0, (sy_call_t *)sys_cap_enter, AUE_CAP_ENTER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 516 = cap_enter */ { AS(cap_getmode_args), (sy_call_t *)sys_cap_getmode, AUE_CAP_GETMODE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 517 = cap_getmode */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 518 = pdfork */ @@ -593,4 +593,9 @@ struct sysent freebsd32_sysent[] = { { AS(freebsd32_posix_fallocate_args), (sy_call_t *)freebsd32_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */ { AS(freebsd32_posix_fadvise_args), (sy_call_t *)freebsd32_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */ { AS(freebsd32_wait6_args), (sy_call_t *)freebsd32_wait6, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = freebsd32_wait6 */ + { AS(cap_rights_limit_args), (sy_call_t *)sys_cap_rights_limit, AUE_CAP_RIGHTS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 533 = cap_rights_limit */ + { AS(cap_ioctls_limit_args), (sy_call_t *)sys_cap_ioctls_limit, AUE_CAP_IOCTLS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 534 = cap_ioctls_limit */ + { AS(cap_ioctls_get_args), (sy_call_t *)sys_cap_ioctls_get, AUE_CAP_IOCTLS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 535 = cap_ioctls_get */ + { AS(cap_fcntls_limit_args), (sy_call_t *)sys_cap_fcntls_limit, AUE_CAP_FCNTLS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 536 = cap_fcntls_limit */ + { AS(cap_fcntls_get_args), (sy_call_t *)sys_cap_fcntls_get, AUE_CAP_FCNTLS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 537 = cap_fcntls_get */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index 36a646c..e2d7adb 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -2956,9 +2956,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } - /* cap_getrights */ + /* cap_rights_get */ case 515: { - struct cap_getrights_args *p = params; + struct cap_rights_get_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->rightsp; /* uint64_t * */ *n_args = 2; @@ -3088,6 +3088,48 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 6; break; } + /* cap_rights_limit */ + case 533: { + struct cap_rights_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = p->rights; /* uint64_t */ + *n_args = 2; + break; + } + /* cap_ioctls_limit */ + case 534: { + struct cap_ioctls_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* const u_long * */ + uarg[2] = p->ncmds; /* size_t */ + *n_args = 3; + break; + } + /* cap_ioctls_get */ + case 535: { + struct cap_ioctls_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* u_long * */ + uarg[2] = p->maxcmds; /* size_t */ + *n_args = 3; + break; + } + /* cap_fcntls_limit */ + case 536: { + struct cap_fcntls_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = p->fcntlrights; /* uint32_t */ + *n_args = 2; + break; + } + /* cap_fcntls_get */ + case 537: { + struct cap_fcntls_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->fcntlrightsp; /* uint32_t * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -8002,7 +8044,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* cap_getrights */ + /* cap_rights_get */ case 515: switch(ndx) { case 0: @@ -8243,6 +8285,77 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* cap_rights_limit */ + case 533: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint64_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_limit */ + case 534: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const u_long *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_get */ + case 535: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "u_long *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* cap_fcntls_limit */ + case 536: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* cap_fcntls_get */ + case 537: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint32_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -9938,7 +10051,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* cap_getrights */ + /* cap_rights_get */ case 515: if (ndx == 0 || ndx == 1) p = "int"; @@ -10005,6 +10118,31 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* cap_rights_limit */ + case 533: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_ioctls_limit */ + case 534: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_ioctls_get */ + case 535: + if (ndx == 0 || ndx == 1) + p = "ssize_t"; + break; + /* cap_fcntls_limit */ + case 536: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_fcntls_get */ + case 537: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 4106447..6552d13 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -963,7 +963,7 @@ struct shmid_ds32 *buf); } 513 AUE_LPATHCONF NOPROTO { int lpathconf(char *path, int name); } 514 AUE_CAP_NEW NOPROTO { int cap_new(int fd, uint64_t rights); } -515 AUE_CAP_GETRIGHTS NOPROTO { int cap_getrights(int fd, \ +515 AUE_CAP_RIGHTS_GET NOPROTO { int cap_rights_get(int fd, \ uint64_t *rightsp); } 516 AUE_CAP_ENTER NOPROTO { int cap_enter(void); } 517 AUE_CAP_GETMODE NOPROTO { int cap_getmode(u_int *modep); } @@ -1005,3 +1005,13 @@ struct wrusage32 *wrusage, \ siginfo_t *info); } +533 AUE_CAP_RIGHTS_LIMIT NOPROTO { int cap_rights_limit(int fd, \ + uint64_t rights); } +534 AUE_CAP_IOCTLS_LIMIT NOPROTO { int cap_ioctls_limit(int fd, \ + const u_long *cmds, size_t ncmds); } +535 AUE_CAP_IOCTLS_GET NOPROTO { ssize_t cap_ioctls_get(int fd, \ + u_long *cmds, size_t maxcmds); } +536 AUE_CAP_FCNTLS_LIMIT NOPROTO { int cap_fcntls_limit(int fd, \ + uint32_t fcntlrights); } +537 AUE_CAP_FCNTLS_GET NOPROTO { int cap_fcntls_get(int fd, \ + uint32_t *fcntlrightsp); } diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 0318a5c..346d178 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -154,6 +154,7 @@ linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mod SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { PROC_UNLOCK(p); sx_unlock(&proctree_lock); + /* XXXPJD: Verify if TIOCSCTTY is allowed. */ if (fp->f_type == DTYPE_VNODE) (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, td); @@ -1038,11 +1039,11 @@ linux_pread(td, uap) error = sys_pread(td, &bsd); if (error == 0) { - /* This seems to violate POSIX but linux does it */ - if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0) - return (error); + /* This seems to violate POSIX but linux does it */ + if ((error = fgetvp(td, uap->fd, CAP_PREAD, &vp)) != 0) + return (error); if (vp->v_type == VDIR) { - vrele(vp); + vrele(vp); return (EISDIR); } vrele(vp); diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index 23abaf1..e094997 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -566,7 +566,7 @@ ndis_convert_res(arg) return (ENOMEM); rl->cprl_version = 5; - rl->cprl_version = 1; + rl->cprl_revision = 1; rl->cprl_count = sc->ndis_rescnt; prd = rl->cprl_partial_descs; diff --git a/sys/compat/svr4/svr4_fcntl.c b/sys/compat/svr4/svr4_fcntl.c index b9d3ace..86fab78 100644 --- a/sys/compat/svr4/svr4_fcntl.c +++ b/sys/compat/svr4/svr4_fcntl.c @@ -265,14 +265,14 @@ fd_revoke(td, fd) /* * If we ever want to support Capsicum on SVR4 processes (unlikely) * or FreeBSD grows a native frevoke() (more likely), we will need a - * CAP_REVOKE here. + * CAP_FREVOKE here. * - * In the meantime, use CAP_MASK_VALID: if a SVR4 process wants to + * In the meantime, use CAP_ALL: if a SVR4 process wants to * do an frevoke(), it needs to do it on either a regular file * descriptor or a fully-privileged capability (which is effectively * the same as a non-capability-restricted file descriptor). */ - if ((error = fgetvp(td, fd, CAP_MASK_VALID, &vp)) != 0) + if ((error = fgetvp(td, fd, CAP_ALL, &vp)) != 0) return (error); if (vp->v_type != VCHR && vp->v_type != VBLK) { diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c index 967169b..0fbba07 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -197,22 +197,24 @@ svr4_fil_ioctl(fp, td, retval, fd, cmd, data) u_long cmd; caddr_t data; { - int error; - int num; struct filedesc *fdp = td->td_proc->p_fd; + struct filedescent *fde; + int error, num; *retval = 0; switch (cmd) { case SVR4_FIOCLEX: FILEDESC_XLOCK(fdp); - fdp->fd_ofileflags[fd] |= UF_EXCLOSE; + fde = &fdp->fd_ofiles[fd]; + fde->fde_flags |= UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); return 0; case SVR4_FIONCLEX: FILEDESC_XLOCK(fdp); - fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE; + fde = &fdp->fd_ofiles[fd]; + fde->fde_flags &= ~UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); return 0; diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c index d6bc4eb..0cfaeae 100644 --- a/sys/compat/svr4/svr4_misc.c +++ b/sys/compat/svr4/svr4_misc.c @@ -247,10 +247,8 @@ svr4_sys_getdents64(td, uap) DPRINTF(("svr4_sys_getdents64(%d, *, %d)\n", uap->fd, uap->nbytes)); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, - CAP_READ | CAP_SEEK, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) return (error); - } if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -426,8 +424,7 @@ svr4_sys_getdents(td, uap) if (uap->nbytes < 0) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, - CAP_READ | CAP_SEEK, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c index 27014e3..1c7e83e 100644 --- a/sys/compat/svr4/svr4_stream.c +++ b/sys/compat/svr4/svr4_stream.c @@ -1449,7 +1449,7 @@ svr4_sys_putmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, CAP_WRITE, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_SEND, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("putmsg: bad fp\n"); #endif @@ -1621,7 +1621,7 @@ svr4_sys_getmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, CAP_READ, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_RECV, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("getmsg: bad fp\n"); #endif diff --git a/sys/conf/options.sparc64 b/sys/conf/options.sparc64 index bc6af5a..883db16 100644 --- a/sys/conf/options.sparc64 +++ b/sys/conf/options.sparc64 @@ -23,7 +23,6 @@ PSM_DEBUG opt_psm.h PSM_HOOKRESUME opt_psm.h PSM_RESETAFTERSUSPEND opt_psm.h -DEBUGGER_ON_POWERFAIL opt_psycho.h PSYCHO_DEBUG opt_psycho.h SCHIZO_DEBUG opt_schizo.h diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c index 9f315b6..d4c7383 100644 --- a/sys/dev/aac/aac.c +++ b/sys/dev/aac/aac.c @@ -117,7 +117,7 @@ static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); -struct aac_interface aac_sa_interface = { +const struct aac_interface aac_sa_interface = { aac_sa_get_fwstatus, aac_sa_qnotify, aac_sa_get_istatus, @@ -142,7 +142,7 @@ static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); static int aac_rx_get_outb_queue(struct aac_softc *sc); static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); -struct aac_interface aac_rx_interface = { +const struct aac_interface aac_rx_interface = { aac_rx_get_fwstatus, aac_rx_qnotify, aac_rx_get_istatus, @@ -169,7 +169,7 @@ static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); static int aac_rkt_get_outb_queue(struct aac_softc *sc); static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); -struct aac_interface aac_rkt_interface = { +const struct aac_interface aac_rkt_interface = { aac_rkt_get_fwstatus, aac_rkt_qnotify, aac_rkt_get_istatus, @@ -183,8 +183,8 @@ struct aac_interface aac_rkt_interface = { }; /* Debugging and Diagnostics */ -static void aac_describe_controller(struct aac_softc *sc); -static char *aac_describe_code(struct aac_code_lookup *table, +static void aac_describe_controller(struct aac_softc *sc); +static const char *aac_describe_code(const struct aac_code_lookup *table, u_int32_t code); /* Management Interface */ @@ -222,7 +222,7 @@ static struct cdevsw aac_cdevsw = { static MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); /* sysctl node */ -static SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); +SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); /* * Device Interface @@ -634,8 +634,8 @@ aac_free(struct aac_softc *sc) if (sc->aac_intr) bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); if (sc->aac_irq != NULL) - bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, - sc->aac_irq); + bus_release_resource(sc->aac_dev, SYS_RES_IRQ, + rman_get_rid(sc->aac_irq), sc->aac_irq); /* destroy data-transfer DMA tag */ if (sc->aac_buffer_dmat) @@ -648,10 +648,10 @@ aac_free(struct aac_softc *sc) /* release the register window mapping */ if (sc->aac_regs_res0 != NULL) bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, - sc->aac_regs_rid0, sc->aac_regs_res0); + rman_get_rid(sc->aac_regs_res0), sc->aac_regs_res0); if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, - sc->aac_regs_rid1, sc->aac_regs_res1); + rman_get_rid(sc->aac_regs_res1), sc->aac_regs_res1); } /* @@ -1333,9 +1333,6 @@ aac_bio_complete(struct aac_command *cm) } else { bp->bio_error = EIO; bp->bio_flags |= BIO_ERROR; - /* pass an error string out to the disk layer */ - bp->bio_driver1 = aac_describe_code(aac_command_status_table, - status); } aac_biodone(bp); } @@ -1687,7 +1684,7 @@ static int aac_check_firmware(struct aac_softc *sc) { u_int32_t code, major, minor, options = 0, atu_size = 0; - int status; + int rid, status; time_t then; fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); @@ -1765,7 +1762,7 @@ aac_check_firmware(struct aac_softc *sc) sc->flags |= AAC_FLAGS_SG_64BIT; } if ((options & AAC_SUPPORTED_NEW_COMM) - && sc->aac_if.aif_send_command) + && sc->aac_if->aif_send_command) sc->flags |= AAC_FLAGS_NEW_COMM; if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) sc->flags |= AAC_FLAGS_ARRAY_64BIT; @@ -1776,17 +1773,15 @@ aac_check_firmware(struct aac_softc *sc) /* Remap mem. resource, if required */ if ((sc->flags & AAC_FLAGS_NEW_COMM) && - atu_size > rman_get_size(sc->aac_regs_res1)) { - bus_release_resource( - sc->aac_dev, SYS_RES_MEMORY, - sc->aac_regs_rid1, sc->aac_regs_res1); - sc->aac_regs_res1 = bus_alloc_resource( - sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1, - 0ul, ~0ul, atu_size, RF_ACTIVE); + atu_size > rman_get_size(sc->aac_regs_res1)) { + rid = rman_get_rid(sc->aac_regs_res1); + bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, rid, + sc->aac_regs_res1); + sc->aac_regs_res1 = bus_alloc_resource(sc->aac_dev, + SYS_RES_MEMORY, &rid, 0ul, ~0ul, atu_size, RF_ACTIVE); if (sc->aac_regs_res1 == NULL) { sc->aac_regs_res1 = bus_alloc_resource_any( - sc->aac_dev, SYS_RES_MEMORY, - &sc->aac_regs_rid1, RF_ACTIVE); + sc->aac_dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->aac_regs_res1 == NULL) { device_printf(sc->aac_dev, "couldn't allocate register window\n"); @@ -1799,7 +1794,6 @@ aac_check_firmware(struct aac_softc *sc) if (sc->aac_hwif == AAC_HWIF_NARK) { sc->aac_regs_res0 = sc->aac_regs_res1; - sc->aac_regs_rid0 = sc->aac_regs_rid1; sc->aac_btag0 = sc->aac_btag1; sc->aac_bhandle0 = sc->aac_bhandle1; } @@ -2003,14 +1997,7 @@ out: static int aac_setup_intr(struct aac_softc *sc) { - sc->aac_irq_rid = 0; - if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, - &sc->aac_irq_rid, - RF_SHAREABLE | - RF_ACTIVE)) == NULL) { - device_printf(sc->aac_dev, "can't allocate interrupt\n"); - return (EINVAL); - } + if (sc->flags & AAC_FLAGS_NEW_COMM) { if (bus_setup_intr(sc->aac_dev, sc->aac_irq, INTR_MPSAFE|INTR_TYPE_BIO, NULL, @@ -2119,7 +2106,7 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, * Note that the queue implementation here is a little funky; neither the PI or * CI will ever be zero. This behaviour is a controller feature. */ -static struct { +static const struct { int size; int notify; } aac_qinfo[] = { @@ -2786,8 +2773,8 @@ aac_describe_controller(struct aac_softc *sc) * Look up a text description of a numeric error code and return a pointer to * same. */ -static char * -aac_describe_code(struct aac_code_lookup *table, u_int32_t code) +static const char * +aac_describe_code(const struct aac_code_lookup *table, u_int32_t code) { int i; diff --git a/sys/dev/aac/aac_cam.c b/sys/dev/aac/aac_cam.c index 7f0d7ee..60ead24 100644 --- a/sys/dev/aac/aac_cam.c +++ b/sys/dev/aac/aac_cam.c @@ -92,7 +92,7 @@ static device_method_t aac_pass_methods[] = { DEVMETHOD(device_probe, aac_cam_probe), DEVMETHOD(device_attach, aac_cam_attach), DEVMETHOD(device_detach, aac_cam_detach), - { 0, 0 } + DEVMETHOD_END }; static driver_t aac_pass_driver = { @@ -101,7 +101,7 @@ static driver_t aac_pass_driver = { sizeof(struct aac_cam) }; -DRIVER_MODULE(aacp, aac, aac_pass_driver, aac_pass_devclass, 0, 0); +DRIVER_MODULE(aacp, aac, aac_pass_driver, aac_pass_devclass, NULL, NULL); MODULE_DEPEND(aacp, cam, 1, 1, 1); static MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info"); @@ -685,4 +685,3 @@ aac_cam_term_io(struct cam_sim *sim, union ccb *ccb) { return (CAM_UA_TERMIO); } - diff --git a/sys/dev/aac/aac_disk.c b/sys/dev/aac/aac_disk.c index f2f6636..082be9b 100644 --- a/sys/dev/aac/aac_disk.c +++ b/sys/dev/aac/aac_disk.c @@ -73,7 +73,7 @@ static device_method_t aac_disk_methods[] = { DEVMETHOD(device_probe, aac_disk_probe), DEVMETHOD(device_attach, aac_disk_attach), DEVMETHOD(device_detach, aac_disk_detach), - { 0, 0 } + DEVMETHOD_END }; static driver_t aac_disk_driver = { @@ -82,7 +82,7 @@ static driver_t aac_disk_driver = { sizeof(struct aac_disk) }; -DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); +DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, NULL, NULL); /* * Handle open from generic layer. diff --git a/sys/dev/aac/aac_pci.c b/sys/dev/aac/aac_pci.c index 163c5ea..f768c8b 100644 --- a/sys/dev/aac/aac_pci.c +++ b/sys/dev/aac/aac_pci.c @@ -60,6 +60,11 @@ __FBSDID("$FreeBSD$"); static int aac_pci_probe(device_t dev); static int aac_pci_attach(device_t dev); +static int aac_enable_msi = 1; +TUNABLE_INT("hw.aac.enable_msi", &aac_enable_msi); +SYSCTL_INT(_hw_aac, OID_AUTO, enable_msi, CTLFLAG_RDTUN, &aac_enable_msi, 0, + "Enable MSI interrupts"); + static device_method_t aac_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aac_pci_probe), @@ -79,11 +84,10 @@ static driver_t aac_pci_driver = { static devclass_t aac_devclass; -DRIVER_MODULE(aac, pci, aac_pci_driver, aac_devclass, 0, 0); +DRIVER_MODULE(aac, pci, aac_pci_driver, aac_devclass, NULL, NULL); MODULE_DEPEND(aac, pci, 1, 1, 1); - -struct aac_ident +static const struct aac_ident { u_int16_t vendor; u_int16_t device; @@ -91,7 +95,7 @@ struct aac_ident u_int16_t subdevice; int hwif; int quirks; - char *desc; + const char *desc; } aac_identifiers[] = { {0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, 0, "Dell PERC 2/Si"}, @@ -139,7 +143,6 @@ struct aac_ident "Adaptec SCSI RAID 2230S"}, {0x9005, 0x0286, 0x9005, 0x028d, AAC_HWIF_RKT, 0, "Adaptec SCSI RAID 2130S"}, - {0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB | AAC_FLAGS_256FIBS, "Adaptec SCSI RAID 2200S"}, {0x9005, 0x0285, 0x17aa, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB | @@ -276,7 +279,8 @@ struct aac_ident "AOC-USAS-S8iR-LP"}, {0, 0, 0, 0, 0, 0, 0} }; -struct aac_ident + +static const struct aac_ident aac_family_identifiers[] = { {0x9005, 0x0285, 0, 0, AAC_HWIF_I960RX, 0, "Adaptec RAID Controller"}, @@ -285,10 +289,10 @@ aac_family_identifiers[] = { {0, 0, 0, 0, 0, 0, 0} }; -static struct aac_ident * +static const struct aac_ident * aac_find_ident(device_t dev) { - struct aac_ident *m; + const struct aac_ident *m; u_int16_t vendid, devid, sub_vendid, sub_devid; vendid = pci_get_vendor(dev); @@ -317,7 +321,7 @@ aac_find_ident(device_t dev) static int aac_pci_probe(device_t dev) { - struct aac_ident *id; + const struct aac_ident *id; fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); @@ -335,9 +339,8 @@ static int aac_pci_attach(device_t dev) { struct aac_softc *sc; - struct aac_ident *id; - int error; - u_int32_t command; + const struct aac_ident *id; + int count, error, reg, rid; fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); @@ -345,7 +348,6 @@ aac_pci_attach(device_t dev) * Initialise softc. */ sc = device_get_softc(dev); - bzero(sc, sizeof(*sc)); sc->aac_dev = dev; /* assume failure is 'not configured' */ @@ -354,55 +356,66 @@ aac_pci_attach(device_t dev) /* * Verify that the adapter is correctly set up in PCI space. */ - command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2); - command |= PCIM_CMD_BUSMASTEREN; - pci_write_config(dev, PCIR_COMMAND, command, 2); - command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2); - if (!(command & PCIM_CMD_BUSMASTEREN)) { - device_printf(sc->aac_dev, "can't enable bus-master feature\n"); - goto out; - } - if ((command & PCIM_CMD_MEMEN) == 0) { - device_printf(sc->aac_dev, "memory window not available\n"); + pci_enable_busmaster(dev); + if (!(pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_BUSMASTEREN)) { + device_printf(dev, "can't enable bus-master feature\n"); goto out; } /* - * Allocate the PCI register window. + * Allocate the PCI register window(s). */ - sc->aac_regs_rid0 = PCIR_BAR(0); - if ((sc->aac_regs_res0 = bus_alloc_resource_any(sc->aac_dev, - SYS_RES_MEMORY, &sc->aac_regs_rid0, RF_ACTIVE)) == NULL) { - device_printf(sc->aac_dev, - "couldn't allocate register window 0\n"); + rid = PCIR_BAR(0); + if ((sc->aac_regs_res0 = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) { + device_printf(dev, "can't allocate register window 0\n"); goto out; } sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); if (sc->aac_hwif == AAC_HWIF_NARK) { - sc->aac_regs_rid1 = PCIR_BAR(1); - if ((sc->aac_regs_res1 = bus_alloc_resource_any(sc->aac_dev, - SYS_RES_MEMORY, &sc->aac_regs_rid1, RF_ACTIVE)) == NULL) { - device_printf(sc->aac_dev, - "couldn't allocate register window 1\n"); + rid = PCIR_BAR(1); + if ((sc->aac_regs_res1 = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) { + device_printf(dev, + "can't allocate register window 1\n"); goto out; } sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); } else { sc->aac_regs_res1 = sc->aac_regs_res0; - sc->aac_regs_rid1 = sc->aac_regs_rid0; sc->aac_btag1 = sc->aac_btag0; sc->aac_bhandle1 = sc->aac_bhandle0; } /* + * Allocate the interrupt. + */ + rid = 0; + count = 0; + if (aac_enable_msi != 0 && pci_find_cap(dev, PCIY_MSI, ®) == 0) { + count = pci_msi_count(dev); + if (count > 1) + count = 1; + else + count = 0; + if (count == 1 && pci_alloc_msi(dev, &count) == 0) + rid = 1; + } + if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, + &rid, RF_ACTIVE | (count != 0 ? 0 : RF_SHAREABLE))) == NULL) { + device_printf(dev, "can't allocate interrupt\n"); + goto out; + } + + /* * Allocate the parent bus DMA tag appropriate for our PCI interface. * * Note that some of these controllers are 64-bit capable. */ - if (bus_dma_tag_create(bus_get_dma_tag(sc->aac_dev), /* parent */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ PAGE_SIZE, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -413,7 +426,7 @@ aac_pci_attach(device_t dev) 0, /* flags */ NULL, NULL, /* No locking needed */ &sc->aac_parent_dmat)) { - device_printf(sc->aac_dev, "can't allocate parent DMA tag\n"); + device_printf(dev, "can't allocate parent DMA tag\n"); goto out; } @@ -427,19 +440,19 @@ aac_pci_attach(device_t dev) case AAC_HWIF_I960RX: case AAC_HWIF_NARK: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for i960Rx/NARK"); - sc->aac_if = aac_rx_interface; + sc->aac_if = &aac_rx_interface; break; case AAC_HWIF_STRONGARM: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for StrongARM"); - sc->aac_if = aac_sa_interface; + sc->aac_if = &aac_sa_interface; break; case AAC_HWIF_RKT: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for Rocket/MIPS"); - sc->aac_if = aac_rkt_interface; + sc->aac_if = &aac_rkt_interface; break; default: sc->aac_hwif = AAC_HWIF_UNKNOWN; - device_printf(sc->aac_dev, "unknown hardware type\n"); + device_printf(dev, "unknown hardware type\n"); error = ENXIO; goto out; } @@ -472,7 +485,7 @@ static device_method_t aacch_methods[] = { DEVMETHOD(device_probe, aacch_probe), DEVMETHOD(device_attach, aacch_attach), DEVMETHOD(device_detach, aacch_detach), - { 0, 0 } + DEVMETHOD_END }; struct aacch_softc { @@ -486,7 +499,7 @@ static driver_t aacch_driver = { }; static devclass_t aacch_devclass; -DRIVER_MODULE(aacch, pci, aacch_driver, aacch_devclass, 0, 0); +DRIVER_MODULE(aacch, pci, aacch_driver, aacch_devclass, NULL, NULL); static int aacch_probe(device_t dev) diff --git a/sys/dev/aac/aac_tables.h b/sys/dev/aac/aac_tables.h index fe687fb..6f52d5d 100644 --- a/sys/dev/aac/aac_tables.h +++ b/sys/dev/aac/aac_tables.h @@ -27,13 +27,14 @@ * $FreeBSD$ */ +#if 0 /* * Status codes for block read/write commands, etc. * * XXX many of these would not normally be returned, as they are * relevant only to FSA operations. */ -static struct aac_code_lookup aac_command_status_table[] = { +static const struct aac_code_lookup aac_command_status_table[] = { {"OK", ST_OK}, {"operation not permitted", ST_PERM}, {"not found", ST_NOENT}, @@ -75,8 +76,9 @@ static struct aac_code_lookup aac_command_status_table[] = { }; #define AAC_COMMAND_STATUS(x) aac_describe_code(aac_command_status_table, x) +#endif -static struct aac_code_lookup aac_cpu_variant[] = { +static const struct aac_code_lookup aac_cpu_variant[] = { {"i960JX", CPUI960_JX}, {"i960CX", CPUI960_CX}, {"i960HX", CPUI960_HX}, @@ -93,7 +95,7 @@ static struct aac_code_lookup aac_cpu_variant[] = { {"Unknown processor", 0} }; -static struct aac_code_lookup aac_battery_platform[] = { +static const struct aac_code_lookup aac_battery_platform[] = { {"required battery present", PLATFORM_BAT_REQ_PRESENT}, {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, @@ -103,7 +105,7 @@ static struct aac_code_lookup aac_battery_platform[] = { {"unknown battery platform", 0} }; -static struct aac_code_lookup aac_container_types[] = { +static const struct aac_code_lookup aac_container_types[] = { {"Volume", CT_VOLUME}, {"RAID 1 (Mirror)", CT_MIRROR}, {"RAID 0 (Stripe)", CT_STRIPE}, @@ -126,4 +128,3 @@ static struct aac_code_lookup aac_container_types[] = { {NULL, 0}, {"unknown", 0} }; - diff --git a/sys/dev/aac/aacvar.h b/sys/dev/aac/aacvar.h index d994acf..6dc7795 100644 --- a/sys/dev/aac/aacvar.h +++ b/sys/dev/aac/aacvar.h @@ -33,10 +33,13 @@ #include <sys/callout.h> #include <sys/lock.h> #include <sys/mutex.h> -#include <sys/taskqueue.h> #include <sys/selinfo.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <geom/geom_disk.h> +SYSCTL_DECL(_hw_aac); + #define AAC_TYPE_DEVO 1 #define AAC_TYPE_ALPHA 2 #define AAC_TYPE_BETA 3 @@ -242,28 +245,28 @@ struct aac_interface int (*aif_get_outb_queue)(struct aac_softc *sc); void (*aif_set_outb_queue)(struct aac_softc *sc, int index); }; -extern struct aac_interface aac_rx_interface; -extern struct aac_interface aac_sa_interface; -extern struct aac_interface aac_fa_interface; -extern struct aac_interface aac_rkt_interface; - -#define AAC_GET_FWSTATUS(sc) ((sc)->aac_if.aif_get_fwstatus((sc))) -#define AAC_QNOTIFY(sc, qbit) ((sc)->aac_if.aif_qnotify((sc), (qbit))) -#define AAC_GET_ISTATUS(sc) ((sc)->aac_if.aif_get_istatus((sc))) -#define AAC_CLEAR_ISTATUS(sc, mask) ((sc)->aac_if.aif_clr_istatus((sc), \ +extern const struct aac_interface aac_rx_interface; +extern const struct aac_interface aac_sa_interface; +extern const struct aac_interface aac_fa_interface; +extern const struct aac_interface aac_rkt_interface; + +#define AAC_GET_FWSTATUS(sc) ((sc)->aac_if->aif_get_fwstatus((sc))) +#define AAC_QNOTIFY(sc, qbit) ((sc)->aac_if->aif_qnotify((sc), (qbit))) +#define AAC_GET_ISTATUS(sc) ((sc)->aac_if->aif_get_istatus((sc))) +#define AAC_CLEAR_ISTATUS(sc, mask) ((sc)->aac_if->aif_clr_istatus((sc), \ (mask))) #define AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3) \ - ((sc)->aac_if.aif_set_mailbox((sc), (command), (arg0), (arg1), (arg2), \ + ((sc)->aac_if->aif_set_mailbox((sc), (command), (arg0), (arg1), (arg2), \ (arg3))) -#define AAC_GET_MAILBOX(sc, mb) ((sc)->aac_if.aif_get_mailbox((sc), \ +#define AAC_GET_MAILBOX(sc, mb) ((sc)->aac_if->aif_get_mailbox((sc), \ (mb))) -#define AAC_MASK_INTERRUPTS(sc) ((sc)->aac_if.aif_set_interrupts((sc), \ +#define AAC_MASK_INTERRUPTS(sc) ((sc)->aac_if->aif_set_interrupts((sc), \ 0)) -#define AAC_UNMASK_INTERRUPTS(sc) ((sc)->aac_if.aif_set_interrupts((sc), \ +#define AAC_UNMASK_INTERRUPTS(sc) ((sc)->aac_if->aif_set_interrupts((sc), \ 1)) -#define AAC_SEND_COMMAND(sc, cm) ((sc)->aac_if.aif_send_command((sc), (cm))) -#define AAC_GET_OUTB_QUEUE(sc) ((sc)->aac_if.aif_get_outb_queue((sc))) -#define AAC_SET_OUTB_QUEUE(sc, idx) ((sc)->aac_if.aif_set_outb_queue((sc), (idx))) +#define AAC_SEND_COMMAND(sc, cm) ((sc)->aac_if->aif_send_command((sc), (cm))) +#define AAC_GET_OUTB_QUEUE(sc) ((sc)->aac_if->aif_get_outb_queue((sc))) +#define AAC_SET_OUTB_QUEUE(sc, idx) ((sc)->aac_if->aif_set_outb_queue((sc), (idx))) #define AAC_MEM0_SETREG4(sc, reg, val) bus_space_write_4(sc->aac_btag0, \ sc->aac_bhandle0, reg, val) @@ -307,14 +310,12 @@ struct aac_softc /* bus connections */ device_t aac_dev; struct resource *aac_regs_res0, *aac_regs_res1; /* reg. if. window */ - int aac_regs_rid0, aac_regs_rid1; /* resource ID */ bus_space_handle_t aac_bhandle0, aac_bhandle1; /* bus space handle */ bus_space_tag_t aac_btag0, aac_btag1; /* bus space tag */ bus_dma_tag_t aac_parent_dmat; /* parent DMA tag */ bus_dma_tag_t aac_buffer_dmat; /* data buffer/command * DMA tag */ struct resource *aac_irq; /* interrupt */ - int aac_irq_rid; void *aac_intr; /* interrupt handle */ eventhandler_tag eh; @@ -339,7 +340,7 @@ struct aac_softc * DMA map */ struct aac_common *aac_common; u_int32_t aac_common_busaddr; - struct aac_interface aac_if; + const struct aac_interface *aac_if; /* command/fib resources */ bus_dma_tag_t aac_fib_dmat; /* DMA tag for allocing FIBs */ @@ -499,7 +500,7 @@ extern void aac_print_aif(struct aac_softc *sc, #endif struct aac_code_lookup { - char *string; + const char *string; u_int32_t code; }; @@ -581,7 +582,6 @@ aac_remove_ ## name (struct aac_command *cm) \ cm->cm_flags &= ~AAC_ON_ ## index; \ AACQ_REMOVE(cm->cm_sc, index); \ } \ -struct hack AACQ_COMMAND_QUEUE(free, AACQ_FREE); AACQ_COMMAND_QUEUE(ready, AACQ_READY); @@ -644,4 +644,3 @@ aac_release_sync_fib(struct aac_softc *sc) mtx_assert(&sc->aac_io_lock, MA_OWNED); } - diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 7f008f7..e58d980 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -168,7 +168,7 @@ static int acpi_cpu_cx_cst(struct acpi_cpu_softc *sc); static void acpi_cpu_startup(void *arg); static void acpi_cpu_startup_cx(struct acpi_cpu_softc *sc); static void acpi_cpu_cx_list(struct acpi_cpu_softc *sc); -static void acpi_cpu_idle(void); +static void acpi_cpu_idle(sbintime_t sbt); static void acpi_cpu_notify(ACPI_HANDLE h, UINT32 notify, void *context); static int acpi_cpu_quirks(void); static int acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARGS); @@ -954,13 +954,13 @@ acpi_cpu_startup_cx(struct acpi_cpu_softc *sc) * interrupts are re-enabled. */ static void -acpi_cpu_idle() +acpi_cpu_idle(sbintime_t sbt) { struct acpi_cpu_softc *sc; struct acpi_cx *cx_next; uint64_t cputicks; uint32_t start_time, end_time; - int bm_active, cx_next_idx, i; + int bm_active, cx_next_idx, i, us; /* * Look up our CPU id to get our softc. If it's NULL, we'll use C1 @@ -980,13 +980,16 @@ acpi_cpu_idle() } /* Find the lowest state that has small enough latency. */ + us = sc->cpu_prev_sleep; + if (sbt >= 0 && us > (sbt >> 12)) + us = (sbt >> 12); cx_next_idx = 0; if (cpu_disable_deep_sleep) i = min(sc->cpu_cx_lowest, sc->cpu_non_c3); else i = sc->cpu_cx_lowest; for (; i >= 0; i--) { - if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) { + if (sc->cpu_cx_states[i].trans_lat * 3 <= us) { cx_next_idx = i; break; } diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index c00bda4..9b9c966 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -147,8 +147,7 @@ hpet_disable(struct hpet_softc *sc) } static int -hpet_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +hpet_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct hpet_timer *mt = (struct hpet_timer *)et->et_priv; struct hpet_timer *t; @@ -156,20 +155,16 @@ hpet_start(struct eventtimer *et, uint32_t fdiv, now; t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]]; - if (period != NULL) { + if (period != 0) { t->mode = 1; - t->div = (sc->freq * (period->frac >> 32)) >> 32; - if (period->sec != 0) - t->div += sc->freq * period->sec; + t->div = (sc->freq * period) >> 32; } else { t->mode = 2; t->div = 0; } - if (first != NULL) { - fdiv = (sc->freq * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += sc->freq * first->sec; - } else + if (first != 0) + fdiv = (sc->freq * first) >> 32; + else fdiv = t->div; if (t->irq < 0) bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); @@ -684,12 +679,9 @@ hpet_attach(device_t dev) if ((t->caps & HPET_TCAP_PER_INT) == 0) t->et.et_quality -= 10; t->et.et_frequency = sc->freq; - t->et.et_min_period.sec = 0; - t->et.et_min_period.frac = - (((uint64_t)(HPET_MIN_CYCLES * 2) << 32) / sc->freq) << 32; - t->et.et_max_period.sec = 0xfffffffeLLU / sc->freq; - t->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->freq) << 32; + t->et.et_min_period = + ((uint64_t)(HPET_MIN_CYCLES * 2) << 32) / sc->freq; + t->et.et_max_period = (0xfffffffeLLU << 32) / sc->freq; t->et.et_start = hpet_start; t->et.et_stop = hpet_stop; t->et.et_priv = &sc->t[i]; diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c index c815d02..d80fcf2 100644 --- a/sys/dev/arcmsr/arcmsr.c +++ b/sys/dev/arcmsr/arcmsr.c @@ -1,16 +1,15 @@ /* -***************************************************************************************** -** O.S : FreeBSD +******************************************************************************** +** OS : FreeBSD ** FILE NAME : arcmsr.c ** BY : Erich Chen, Ching Huang ** Description: SCSI RAID Device Driver for -** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x) SATA/SAS RAID HOST Adapter -** ARCMSR RAID Host adapter -** [RAID controller:INTEL 331(PCI-X) 341(PCI-EXPRESS) chip set] -****************************************************************************************** -************************************************************************ +** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x) +** SATA/SAS RAID HOST Adapter +******************************************************************************** +******************************************************************************** ** -** Copyright (C) 2002 - 2010, Areca Technology Corporation All rights reserved. +** Copyright (C) 2002 - 2012, Areca Technology Corporation All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions @@ -33,7 +32,7 @@ ** 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. -************************************************************************** +******************************************************************************** ** History ** ** REV# DATE NAME DESCRIPTION @@ -73,7 +72,7 @@ ** 1.20.00.23 01/30/2012 Ching Huang Fixed Request requeued and Retrying command ** 1.20.00.24 06/11/2012 Ching Huang Fixed return sense data condition ** 1.20.00.25 08/17/2012 Ching Huang Fixed hotplug device no function on type A adapter -** 1.20.00.26 12/14/2012 Ching Huang Added support ARC1214 +** 1.20.00.26 12/14/2012 Ching Huang Added support ARC1214,1224 ****************************************************************************************** */ @@ -145,7 +144,7 @@ __FBSDID("$FreeBSD$"); #define arcmsr_callout_init(a) callout_init(a); #endif -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.26 2012-12-14" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.26 2013-01-08" #include <dev/arcmsr/arcmsr.h> /* ************************************************************************** @@ -168,7 +167,7 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); static void arcmsr_iop_init(struct AdapterControlBlock *acb); static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); -static void arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, struct QBUFFER *prbuffer); +static u_int32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, struct QBUFFER *prbuffer); static void arcmsr_Write_data_2iop_wqbuffer(struct AdapterControlBlock *acb); static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb); static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag); @@ -212,7 +211,11 @@ static device_method_t arcmsr_methods[]={ DEVMETHOD(device_suspend, arcmsr_suspend), DEVMETHOD(device_resume, arcmsr_resume), +#if __FreeBSD_version >= 803000 DEVMETHOD_END +#else + { 0, 0 } +#endif }; static driver_t arcmsr_driver={ @@ -1381,13 +1384,61 @@ static void arcmsr_poll(struct cam_sim *psim) ************************************************************************** ************************************************************************** */ -static void arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, +static u_int32_t arcmsr_Read_iop_rqbuffer_data_D(struct AdapterControlBlock *acb, + struct QBUFFER *prbuffer) { + + u_int8_t *pQbuffer; + u_int8_t *buf1 = 0; + u_int32_t *iop_data, *buf2 = 0; + u_int32_t iop_len, data_len; + + iop_data = (u_int32_t *)prbuffer->data; + iop_len = (u_int32_t)prbuffer->data_len; + if ( iop_len > 0 ) + { + buf1 = malloc(128, M_DEVBUF, M_NOWAIT | M_ZERO); + buf2 = (u_int32_t *)buf1; + if( buf1 == NULL) + return (0); + data_len = iop_len; + while(data_len >= 4) + { + *buf2++ = *iop_data++; + data_len -= 4; + } + if(data_len) + *buf2 = *iop_data; + buf2 = (u_int32_t *)buf1; + } + while (iop_len > 0) { + pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex]; + *pQbuffer = *buf1; + acb->rqbuf_lastindex++; + /* if last, index number set it to 0 */ + acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + buf1++; + iop_len--; + } + if(buf2) + free( (u_int8_t *)buf2, M_DEVBUF); + /* let IOP know data has been read */ + arcmsr_iop_message_read(acb); + return (1); +} +/* +************************************************************************** +************************************************************************** +*/ +static u_int32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, struct QBUFFER *prbuffer) { u_int8_t *pQbuffer; u_int8_t *iop_data; u_int32_t iop_len; + if(acb->adapter_type == ACB_ADAPTER_TYPE_D) { + return(arcmsr_Read_iop_rqbuffer_data_D(acb, prbuffer)); + } iop_data = (u_int8_t *)prbuffer->data; iop_len = (u_int32_t)prbuffer->data_len; while (iop_len > 0) { @@ -1401,6 +1452,7 @@ static void arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, } /* let IOP know data has been read */ arcmsr_iop_message_read(acb); + return (1); } /* ************************************************************************** @@ -1417,7 +1469,8 @@ static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) my_empty_len = (acb->rqbuf_lastindex - acb->rqbuf_firstindex - 1) & (ARCMSR_MAX_QBUFFER-1); if(my_empty_len >= prbuffer->data_len) { - arcmsr_Read_iop_rqbuffer_data(acb, prbuffer); + if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } else { acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } @@ -1427,6 +1480,50 @@ static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) ********************************************************************** ********************************************************************** */ +static void arcmsr_Write_data_2iop_wqbuffer_D(struct AdapterControlBlock *acb) +{ + u_int8_t *pQbuffer; + struct QBUFFER *pwbuffer; + u_int8_t *buf1 = 0; + u_int32_t *iop_data, *buf2 = 0; + u_int32_t allxfer_len = 0, data_len; + + if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) { + buf1 = malloc(128, M_DEVBUF, M_NOWAIT | M_ZERO); + buf2 = (u_int32_t *)buf1; + if( buf1 == NULL) + return; + + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (u_int32_t *)pwbuffer->data; + while((acb->wqbuf_firstindex != acb->wqbuf_lastindex) + && (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; + *buf1 = *pQbuffer; + acb->wqbuf_firstindex++; + acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + buf1++; + allxfer_len++; + } + pwbuffer->data_len = allxfer_len; + data_len = allxfer_len; + buf1 = (u_int8_t *)buf2; + while(data_len >= 4) + { + *iop_data++ = *buf2++; + data_len -= 4; + } + if(data_len) + *iop_data = *buf2; + free( buf1, M_DEVBUF); + arcmsr_iop_message_wrote(acb); + } +} +/* +********************************************************************** +********************************************************************** +*/ static void arcmsr_Write_data_2iop_wqbuffer(struct AdapterControlBlock *acb) { u_int8_t *pQbuffer; @@ -1434,6 +1531,10 @@ static void arcmsr_Write_data_2iop_wqbuffer(struct AdapterControlBlock *acb) u_int8_t *iop_data; int32_t allxfer_len=0; + if(acb->adapter_type == ACB_ADAPTER_TYPE_D) { + arcmsr_Write_data_2iop_wqbuffer_D(acb); + return; + } if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) { acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); pwbuffer = arcmsr_get_iop_wqbuffer(acb); @@ -2153,7 +2254,8 @@ u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_c acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; prbuffer = arcmsr_get_iop_rqbuffer(acb); - arcmsr_Read_iop_rqbuffer_data(acb, prbuffer); + if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; @@ -2374,7 +2476,8 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb *p acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; prbuffer = arcmsr_get_iop_rqbuffer(acb); - arcmsr_Read_iop_rqbuffer_data(acb, prbuffer); + if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; diff --git a/sys/dev/arcmsr/arcmsr.h b/sys/dev/arcmsr/arcmsr.h index 219372e..95bb6a1 100644 --- a/sys/dev/arcmsr/arcmsr.h +++ b/sys/dev/arcmsr/arcmsr.h @@ -1,17 +1,14 @@ /* -*********************************************************************************************** -** O.S : FreeBSD +******************************************************************************** +** OS : FreeBSD ** FILE NAME : arcmsr.h ** BY : Erich Chen, Ching Huang ** Description: SCSI RAID Device Driver for -** ARECA SATA/SAS RAID HOST Adapter -** [RAID controller:INTEL 331(PCI-X) 341(PCI-EXPRESS) chip set] -*********************************************************************************************** -************************************************************************ -** Copyright (C) 2002 - 2010, Areca Technology Corporation All rights reserved. -** -** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw; ching2048@areca.com.tw +** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x) +** SATA/SAS RAID HOST Adapter +******************************************************************************** +******************************************************************************** +** Copyright (C) 2002 - 2012, Areca Technology Corporation All rights reserved. ** ** Redistribution and use in source and binary forms,with or without ** modification,are permitted provided that the following conditions diff --git a/sys/dev/ath/if_ath_tx_ht.c b/sys/dev/ath/if_ath_tx_ht.c index d382f8f..9921ffa 100644 --- a/sys/dev/ath/if_ath_tx_ht.c +++ b/sys/dev/ath/if_ath_tx_ht.c @@ -236,9 +236,9 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) rate = rt->info[rc[i].rix].rateCode; /* - * XXX only do this for legacy rates? + * Only enable short preamble for legacy rates */ - if (bf->bf_state.bfs_shpream) + if ((! IS_HT_RATE(rate)) && bf->bf_state.bfs_shpream) rate |= rt->info[rc[i].rix].shortPreamble; /* @@ -267,6 +267,19 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) rc[i].flags |= ATH_RC_SGI_FLAG; + /* + * If we have STBC TX enabled and the receiver + * can receive (at least) 1 stream STBC, AND it's + * MCS 0-7, AND we have at least two chains enabled, + * enable STBC. + */ + if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC && + ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM && + (sc->sc_cur_txchainmask > 1) && + HT_RC_2_STREAMS(rate) == 1) { + rc[i].flags |= ATH_RC_STBC_FLAG; + } + /* XXX dual stream? and 3-stream? */ } @@ -459,6 +472,9 @@ ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf) * * It, along with ath_buf_set_rate, must be called -after- a burst * or aggregate is setup. + * + * XXX TODO: it should use the rate series information from the + * ath_buf, rather than recalculating it here! */ static void ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni, @@ -507,34 +523,6 @@ ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni, */ series[i].ChSel = sc->sc_cur_txchainmask; - if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) - series[i].RateFlags |= HAL_RATESERIES_RTS_CTS; - - /* - * Transmit 40MHz frames only if the node has negotiated - * it rather than whether the node is capable of it or not. - * It's subtly different in the hostap case. - */ - if (ni->ni_chw == 40) - series[i].RateFlags |= HAL_RATESERIES_2040; - - /* - * Set short-GI only if the node has advertised it - * the channel width is suitable, and we support it. - * We don't currently have a "negotiated" set of bits - - * ni_htcap is what the remote end sends, not what this - * node is capable of. - */ - if (ni->ni_chw == 40 && - ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 && - ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) - series[i].RateFlags |= HAL_RATESERIES_HALFGI; - - if (ni->ni_chw == 20 && - ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 && - ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) - series[i].RateFlags |= HAL_RATESERIES_HALFGI; - /* * Setup rate and TX power cap for this series. */ @@ -542,23 +530,55 @@ ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni, series[i].RateIndex = rc[i].rix; series[i].tx_power_cap = 0x3f; /* XXX for now */ - /* - * If we have STBC TX enabled and the receiver - * can receive (at least) 1 stream STBC, AND it's - * MCS 0-7, AND we have at least two chains enabled, - * enable STBC. + * Enable RTS/CTS as appropriate. */ - if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC && - ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM && - (sc->sc_cur_txchainmask > 1) && - HT_RC_2_STREAMS(series[i].Rate) == 1) { - series[i].RateFlags |= HAL_RATESERIES_STBC; - } + if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) + series[i].RateFlags |= HAL_RATESERIES_RTS_CTS; - /* - * XXX TODO: LDPC if it's possible - */ + + if (IS_HT_RATE(rt->info[rc[i].rix].rateCode)) { + /* + * Transmit 40MHz frames only if the node has negotiated + * it rather than whether the node is capable of it or not. + * It's subtly different in the hostap case. + */ + if (ni->ni_chw == 40) + series[i].RateFlags |= HAL_RATESERIES_2040; + + /* + * Set short-GI only if the node has advertised it + * the channel width is suitable, and we support it. + * We don't currently have a "negotiated" set of bits - + * ni_htcap is what the remote end sends, not what this + * node is capable of. + */ + if (ni->ni_chw == 40 && + ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 && + ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) + series[i].RateFlags |= HAL_RATESERIES_HALFGI; + + if (ni->ni_chw == 20 && + ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 && + ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) + series[i].RateFlags |= HAL_RATESERIES_HALFGI; + + /* + * If we have STBC TX enabled and the receiver + * can receive (at least) 1 stream STBC, AND it's + * MCS 0-7, AND we have at least two chains enabled, + * enable STBC. + */ + if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC && + ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM && + (sc->sc_cur_txchainmask > 1) && + HT_RC_2_STREAMS(series[i].Rate) == 1) { + series[i].RateFlags |= HAL_RATESERIES_STBC; + } + /* + * XXX TODO: LDPC if it's possible + */ + } /* * PktDuration doesn't include slot, ACK, RTS, etc timing - diff --git a/sys/dev/ath/if_athrate.h b/sys/dev/ath/if_athrate.h index d07c9ca..918823f 100644 --- a/sys/dev/ath/if_athrate.h +++ b/sys/dev/ath/if_athrate.h @@ -84,6 +84,8 @@ void ath_rate_detach(struct ath_ratectrl *); #define ATH_RC_SGI_FLAG 0x04 /* use short-GI */ #define ATH_RC_HT_FLAG 0x08 /* use HT */ #define ATH_RC_RTSCTS_FLAG 0x10 /* enable RTS/CTS protection */ +#define ATH_RC_STBC_FLAG 0x20 /* enable STBC */ +#define ATH_RC_LDPC_FLAG 0x40 /* enable STBC */ struct ath_rc_series { uint8_t rix; /* ratetable index, not rate code */ diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index 2471f19..032ca5f 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -95,7 +95,7 @@ __FBSDID("$FreeBSD$"); /****************************************************************************/ #define BCE_DEVDESC_MAX 64 -static struct bce_type bce_devs[] = { +static const struct bce_type bce_devs[] = { /* BCM5706C Controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3101, "HP NC370T Multifunction Gigabit Server Adapter" }, @@ -161,7 +161,7 @@ static struct bce_type bce_devs[] = { /****************************************************************************/ /* Supported Flash NVRAM device data. */ /****************************************************************************/ -static struct flash_spec flash_table[] = +static const struct flash_spec flash_table[] = { #define BUFFERED_FLAGS (BCE_NV_BUFFERED | BCE_NV_TRANSLATE) #define NONBUFFERED_FLAGS (BCE_NV_WREN) @@ -258,7 +258,7 @@ static struct flash_spec flash_table[] = * logical-to-physical mapping is required in the * driver. */ -static struct flash_spec flash_5709 = { +static const struct flash_spec flash_5709 = { .flags = BCE_NV_BUFFERED, .page_bits = BCM5709_FLASH_PAGE_BITS, .page_size = BCM5709_FLASH_PAGE_SIZE, @@ -481,8 +481,8 @@ MODULE_DEPEND(bce, pci, 1, 1, 1); MODULE_DEPEND(bce, ether, 1, 1, 1); MODULE_DEPEND(bce, miibus, 1, 1, 1); -DRIVER_MODULE(bce, pci, bce_driver, bce_devclass, 0, 0); -DRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, 0, 0); +DRIVER_MODULE(bce, pci, bce_driver, bce_devclass, NULL, NULL); +DRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, NULL, NULL); /****************************************************************************/ @@ -647,7 +647,7 @@ SYSCTL_UINT(_hw_bce, OID_AUTO, rx_ticks, CTLFLAG_RDTUN, static int bce_probe(device_t dev) { - struct bce_type *t; + const struct bce_type *t; struct bce_softc *sc; char *descbuf; u16 vid = 0, did = 0, svid = 0, sdid = 0; @@ -655,7 +655,6 @@ bce_probe(device_t dev) t = bce_devs; sc = device_get_softc(dev); - bzero(sc, sizeof(struct bce_softc)); sc->bce_unit = device_get_unit(dev); sc->bce_dev = dev; @@ -1040,7 +1039,7 @@ bce_attach(device_t dev) struct bce_softc *sc; struct ifnet *ifp; u32 val; - int error, rid, rc = 0; + int count, error, rc = 0, rid; sc = device_get_softc(dev); sc->bce_dev = dev; @@ -1077,6 +1076,7 @@ bce_attach(device_t dev) bce_probe_pci_caps(dev, sc); rid = 1; + count = 0; #if 0 /* Try allocating MSI-X interrupts. */ if ((sc->bce_cap_flags & BCE_MSIX_CAPABLE_FLAG) && @@ -1084,14 +1084,14 @@ bce_attach(device_t dev) ((sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE)) != NULL)) { - msi_needed = sc->bce_msi_count = 1; + msi_needed = count = 1; - if (((error = pci_alloc_msix(dev, &sc->bce_msi_count)) != 0) || - (sc->bce_msi_count != msi_needed)) { + if (((error = pci_alloc_msix(dev, &count)) != 0) || + (count != msi_needed)) { BCE_PRINTF("%s(%d): MSI-X allocation failed! Requested = %d," "Received = %d, error = %d\n", __FILE__, __LINE__, - msi_needed, sc->bce_msi_count, error); - sc->bce_msi_count = 0; + msi_needed, count, error); + count = 0; pci_release_msi(dev); bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->bce_res_irq); @@ -1100,19 +1100,18 @@ bce_attach(device_t dev) DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI-X interrupt.\n", __FUNCTION__); sc->bce_flags |= BCE_USING_MSIX_FLAG; - sc->bce_intr = bce_intr; } } #endif /* Try allocating a MSI interrupt. */ if ((sc->bce_cap_flags & BCE_MSI_CAPABLE_FLAG) && - (bce_msi_enable >= 1) && (sc->bce_msi_count == 0)) { - sc->bce_msi_count = 1; - if ((error = pci_alloc_msi(dev, &sc->bce_msi_count)) != 0) { + (bce_msi_enable >= 1) && (count == 0)) { + count = 1; + if ((error = pci_alloc_msi(dev, &count)) != 0) { BCE_PRINTF("%s(%d): MSI allocation failed! " "error = %d\n", __FILE__, __LINE__, error); - sc->bce_msi_count = 0; + count = 0; pci_release_msi(dev); } else { DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI " @@ -1120,23 +1119,19 @@ bce_attach(device_t dev) sc->bce_flags |= BCE_USING_MSI_FLAG; if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) sc->bce_flags |= BCE_ONE_SHOT_MSI_FLAG; - sc->bce_irq_rid = 1; - sc->bce_intr = bce_intr; + rid = 1; } } /* Try allocating a legacy interrupt. */ - if (sc->bce_msi_count == 0) { + if (count == 0) { DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using INTx interrupt.\n", __FUNCTION__); rid = 0; - sc->bce_intr = bce_intr; } sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &rid, RF_SHAREABLE | RF_ACTIVE); - - sc->bce_irq_rid = rid; + &rid, RF_ACTIVE | (count != 0 ? 0 : RF_SHAREABLE)); /* Report any IRQ allocation errors. */ if (sc->bce_res_irq == NULL) { @@ -1635,7 +1630,7 @@ bce_shutdown(device_t dev) static u32 bce_reg_rd(struct bce_softc *sc, u32 offset) { - u32 val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, offset); + u32 val = REG_RD(sc, offset); DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", __FUNCTION__, offset, val); return val; @@ -1653,7 +1648,7 @@ bce_reg_wr16(struct bce_softc *sc, u32 offset, u16 val) { DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%04X\n", __FUNCTION__, offset, val); - bus_space_write_2(sc->bce_btag, sc->bce_bhandle, offset, val); + REG_WR16(sc, offset, val); } @@ -1668,7 +1663,7 @@ bce_reg_wr(struct bce_softc *sc, u32 offset, u32 val) { DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", __FUNCTION__, offset, val); - bus_space_write_4(sc->bce_btag, sc->bce_bhandle, offset, val); + REG_WR(sc, offset, val); } #endif @@ -1879,13 +1874,6 @@ bce_miibus_read_reg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - /* Make sure we are accessing the correct PHY address. */ - if (phy != sc->bce_phy_addr) { - DBPRINT(sc, BCE_INSANE_PHY, "Invalid PHY address %d " - "for PHY read!\n", phy); - return(0); - } - /* * The 5709S PHY is an IEEE Clause 45 PHY * with special mappings to work with IEEE @@ -1968,13 +1956,6 @@ bce_miibus_write_reg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); - /* Make sure we are accessing the correct PHY address. */ - if (phy != sc->bce_phy_addr) { - DBPRINT(sc, BCE_INSANE_PHY, "Invalid PHY address %d " - "for PHY write!\n", phy); - return(0); - } - DB_PRINT_PHY_REG(reg, val); /* @@ -2535,7 +2516,7 @@ bce_init_nvram(struct bce_softc *sc) { u32 val; int j, entry_count, rc = 0; - struct flash_spec *flash; + const struct flash_spec *flash; DBENTER(BCE_VERBOSE_NVRAM); @@ -3949,8 +3930,8 @@ bce_release_resources(struct bce_softc *sc) if (sc->bce_res_irq != NULL) { DBPRINT(sc, BCE_INFO_RESET, "Releasing IRQ.\n"); - bus_release_resource(dev, SYS_RES_IRQ, sc->bce_irq_rid, - sc->bce_res_irq); + bus_release_resource(dev, SYS_RES_IRQ, + rman_get_rid(sc->bce_res_irq), sc->bce_res_irq); } if (sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) { @@ -11650,4 +11631,3 @@ bce_breakpoint(struct bce_softc *sc) return; } #endif - diff --git a/sys/dev/bce/if_bcereg.h b/sys/dev/bce/if_bcereg.h index fc37b2c..37ff5ed 100644 --- a/sys/dev/bce/if_bcereg.h +++ b/sys/dev/bce/if_bcereg.h @@ -622,7 +622,7 @@ struct bce_type { u_int16_t bce_did; u_int16_t bce_svid; u_int16_t bce_sdid; - char *bce_name; + const char *bce_name; }; /****************************************************************************/ @@ -716,7 +716,7 @@ struct flash_spec { u32 page_size; u32 addr_mask; u32 total_size; - u8 *name; + const u8 *name; }; @@ -2001,7 +2001,7 @@ struct l2_fhdr { #define BCE_MISC_ENABLE_CLR_BITS_UMP_ENABLE (1L<<27) #define BCE_MISC_ENABLE_CLR_BITS_RV2P_CMD_SCHEDULER_ENABLE (1L<<28) #define BCE_MISC_ENABLE_CLR_BITS_RSVD_FUTURE_ENABLE (0x7L<<29) -
+ #define BCE_MISC_ENABLE_CLR_DEFAULT 0x17ffffff #define BCE_MISC_CLOCK_CONTROL_BITS 0x00000818 @@ -6318,19 +6318,19 @@ struct fw_info { u32 text_addr; u32 text_len; u32 text_index; - u32 *text; + const u32 *text; /* Data section. */ u32 data_addr; u32 data_len; u32 data_index; - u32 *data; + const u32 *data; /* SBSS section. */ u32 sbss_addr; u32 sbss_len; u32 sbss_index; - u32 *sbss; + const u32 *sbss; /* BSS section. */ u32 bss_addr; @@ -6421,7 +6421,7 @@ struct fw_info { struct bce_softc { - /* Interface info. Must be first!! */ + /* Interface info */ struct ifnet *bce_ifp; /* Parent device handle */ @@ -6451,10 +6451,7 @@ struct bce_softc struct mtx bce_mtx; /* Interrupt handler. */ - driver_intr_t *bce_intr; void *bce_intrhand; - int bce_irq_rid; - int bce_msi_count; /* ASIC Chip ID. */ u32 bce_chipid; @@ -6509,7 +6506,7 @@ struct bce_softc u16 link_speed; /* Flash NVRAM settings */ - struct flash_spec *bce_flash_info; + const struct flash_spec *bce_flash_info; /* Flash NVRAM size */ u32 bce_flash_size; @@ -6518,7 +6515,7 @@ struct bce_softc u32 bce_shmem_base; /* Name string */ - char *bce_name; + const char *bce_name; /* Tracks the version of bootcode firmware. */ char bce_bc_ver[32]; @@ -6834,4 +6831,3 @@ struct bce_softc }; #endif /* __BCEREG_H_DEFINED */ - diff --git a/sys/dev/cas/if_cas.c b/sys/dev/cas/if_cas.c index f98d4f0..eec8fa4 100644 --- a/sys/dev/cas/if_cas.c +++ b/sys/dev/cas/if_cas.c @@ -824,7 +824,8 @@ cas_disable_rx(struct cas_softc *sc) BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); if (cas_bitwait(sc, CAS_MAC_RX_CONF, CAS_MAC_RX_CONF_EN, 0)) return (1); - device_printf(sc->sc_dev, "cannot disable RX MAC\n"); + if (bootverbose) + device_printf(sc->sc_dev, "cannot disable RX MAC\n"); return (0); } @@ -838,7 +839,8 @@ cas_disable_tx(struct cas_softc *sc) BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); if (cas_bitwait(sc, CAS_MAC_TX_CONF, CAS_MAC_TX_CONF_EN, 0)) return (1); - device_printf(sc->sc_dev, "cannot disable TX MAC\n"); + if (bootverbose) + device_printf(sc->sc_dev, "cannot disable TX MAC\n"); return (0); } @@ -1041,7 +1043,8 @@ cas_init_locked(struct cas_softc *sc) /* * Enable infinite bursts for revisions without PCI issues if * applicable. Doing so greatly improves the TX performance on - * !__sparc64__. + * !__sparc64__ (on sparc64, setting CAS_INF_BURST improves TX + * performance only marginally but hurts RX throughput quite a bit). */ CAS_WRITE_4(sc, CAS_INF_BURST, #if !defined(__sparc64__) @@ -2691,7 +2694,10 @@ cas_pci_attach(device_t dev) return (ENXIO); } - pci_enable_busmaster(dev); + /* PCI configuration */ + pci_write_config(dev, PCIR_COMMAND, + pci_read_config(dev, PCIR_COMMAND, 2) | PCIM_CMD_BUSMASTEREN | + PCIM_CMD_MWRICEN | PCIM_CMD_PERRESPEN | PCIM_CMD_SERRESPEN, 2); sc->sc_dev = dev; if (sc->sc_variant == CAS_CAS && pci_get_devid(dev) < 0x02) diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h index 635270c..659f591 100644 --- a/sys/dev/ic/ns16550.h +++ b/sys/dev/ic/ns16550.h @@ -182,6 +182,7 @@ #define com_xoff1 6 /* XOFF 1 character (R/W) */ #define com_xoff2 7 /* XOFF 2 character (R/W) */ +#define DW_REG_USR 31 /* DesignWare derived Uart Status Reg */ #define com_usr 39 /* Octeon 16750/16550 Uart Status Reg */ #define REG_USR com_usr #define USR_TXFIFO_NOTFULL 2 /* Uart TX FIFO Not full */ diff --git a/sys/dev/iscsi/initiator/iscsi.c b/sys/dev/iscsi/initiator/iscsi.c index a93a685..3737b7f 100644 --- a/sys/dev/iscsi/initiator/iscsi.c +++ b/sys/dev/iscsi/initiator/iscsi.c @@ -387,11 +387,11 @@ i_setsoc(isc_session_t *sp, int fd, struct thread *td) if(sp->soc != NULL) isc_stop_receiver(sp); - error = fget(td, fd, CAP_SOCK_ALL, &sp->fp); + error = fget(td, fd, CAP_SOCK_CLIENT, &sp->fp); if(error) return error; - if((error = fgetsock(td, fd, CAP_SOCK_ALL, &sp->soc, 0)) == 0) { + if((error = fgetsock(td, fd, CAP_SOCK_CLIENT, &sp->soc, 0)) == 0) { sp->td = td; isc_start_receiver(sp); } diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index e2401f6..cf2d505 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -2997,7 +2997,7 @@ mfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) cm->cm_frame->stp.sgl.sg64[i].len = ioc->mfi_sgl[i].iov_len; } else { - cm->cm_frame->stp.sgl.sg32[i].len = + cm->cm_frame->stp.sgl.sg32[i].addr = kern_sge[i].phys_addr; cm->cm_frame->stp.sgl.sg32[i].len = ioc->mfi_sgl[i].iov_len; diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c index 7a3e4f7..5e41b0a 100644 --- a/sys/dev/mps/mps.c +++ b/sys/dev/mps/mps.c @@ -136,8 +136,8 @@ mps_diag_reset(struct mps_softc *sc,int sleep_flag) /*Force NO_SLEEP for threads prohibited to sleep * e.a Thread from interrupt handler are prohibited to sleep. - */ - if(curthread->td_pflags & TDP_NOSLEEPING) + */ + if (curthread->td_no_sleeping != 0) sleep_flag = NO_SLEEP; /* Push the magic sequence */ @@ -469,8 +469,8 @@ mps_request_sync(struct mps_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply, uint16_t *data16; int i, count, ioc_sz, residual; int sleep_flags = CAN_SLEEP; - - if(curthread->td_pflags & TDP_NOSLEEPING) + + if (curthread->td_no_sleeping != 0) sleep_flags = NO_SLEEP; /* Step 1 */ diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7632e73..649a494 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -244,7 +244,6 @@ static const struct pci_quirk pci_quirks[] = { * but support MSI just fine. QEMU uses the Intel 82440. */ { 0x12378086, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, - { 0x12751275, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, /* bhyve */ /* * HPET MMIO base address may appear in Bar1 for AMD SB600 SMBus diff --git a/sys/dev/puc/pucdata.c b/sys/dev/puc/pucdata.c index 216a30b..6d933e8 100644 --- a/sys/dev/puc/pucdata.c +++ b/sys/dev/puc/pucdata.c @@ -769,7 +769,7 @@ const struct puc_cfg puc_pci_devices[] = { { 0x1415, 0x9538, 0xffff, 0, "Oxford Semiconductor OX16PCI958 UARTs", - DEFAULT_RCLK * 10, + DEFAULT_RCLK, PUC_PORT_8S, 0x18, 0, 8, }, @@ -918,6 +918,7 @@ const struct puc_cfg puc_pci_devices[] = { DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, + { 0x14d2, 0xa004, 0xffff, 0, "Titan PCI-800H", DEFAULT_RCLK * 8, @@ -1060,7 +1061,7 @@ const struct puc_cfg puc_pci_devices[] = { { 0x9710, 0x9865, 0xa000, 0x3004, "NetMos NM9865 Quad UART", DEFAULT_RCLK, - PUC_PORT_4S, 0x10, 4, 0,0 + PUC_PORT_4S, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3011, @@ -1420,26 +1421,26 @@ static int puc_config_timedia(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { - static uint16_t dual[] = { + static const uint16_t dual[] = { 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, 0xD079, 0 }; - static uint16_t quad[] = { + static const uint16_t quad[] = { 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, 0xB157, 0 }; - static uint16_t octa[] = { + static const uint16_t octa[] = { 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; - static struct { + static const struct { int ports; - uint16_t *ids; + const uint16_t *ids; } subdevs[] = { { 2, dual }, { 4, quad }, diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c index 1044bb6..15199f0 100644 --- a/sys/dev/sdhci/sdhci.c +++ b/sys/dev/sdhci/sdhci.c @@ -573,6 +573,13 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) if (slot->quirks & SDHCI_QUIRK_FORCE_DMA) slot->opt |= SDHCI_HAVE_DMA; + /* + * Use platform-provided transfer backend + * with PIO as a fallback mechanism + */ + if (slot->opt & SDHCI_PLATFORM_TRANSFER) + slot->opt &= ~SDHCI_HAVE_DMA; + if (bootverbose || sdhci_debug) { slot_printf(slot, "%uMHz%s 4bits%s%s%s %s\n", slot->max_clk / 1000000, @@ -909,7 +916,7 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512); } -static void +void sdhci_finish_data(struct sdhci_slot *slot) { struct mmc_data *data = slot->curcmd->data; @@ -1102,13 +1109,23 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) } if (slot->curcmd->error) { /* No need to continue after any error. */ - sdhci_finish_data(slot); + if (slot->flags & PLATFORM_DATA_STARTED) { + slot->flags &= ~PLATFORM_DATA_STARTED; + SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); + } else + sdhci_finish_data(slot); return; } /* Handle PIO interrupt. */ - if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) - sdhci_transfer_pio(slot); + if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) { + if ((slot->opt & SDHCI_PLATFORM_TRANSFER) && + SDHCI_PLATFORM_WILL_HANDLE(slot->bus, slot)) { + SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, &intmask); + slot->flags |= PLATFORM_DATA_STARTED; + } else + sdhci_transfer_pio(slot); + } /* Handle DMA border. */ if (intmask & SDHCI_INT_DMA_END) { struct mmc_data *data = slot->curcmd->data; @@ -1147,8 +1164,13 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); } /* We have got all data. */ - if (intmask & SDHCI_INT_DATA_END) - sdhci_finish_data(slot); + if (intmask & SDHCI_INT_DATA_END) { + if (slot->flags & PLATFORM_DATA_STARTED) { + slot->flags &= ~PLATFORM_DATA_STARTED; + SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); + } else + sdhci_finish_data(slot); + } } static void diff --git a/sys/dev/sdhci/sdhci.h b/sys/dev/sdhci/sdhci.h index 31fbe68..5c46778 100644 --- a/sys/dev/sdhci/sdhci.h +++ b/sys/dev/sdhci/sdhci.h @@ -224,8 +224,9 @@ struct sdhci_slot { device_t dev; /* Slot device */ u_char num; /* Slot number */ u_char opt; /* Slot options */ +#define SDHCI_HAVE_DMA 1 +#define SDHCI_PLATFORM_TRANSFER 2 u_char version; -#define SDHCI_HAVE_DMA 1 uint32_t max_clk; /* Max possible freq */ uint32_t timeout_clk; /* Timeout freq */ bus_dma_tag_t dmatag; @@ -250,6 +251,7 @@ struct sdhci_slot { #define CMD_STARTED 1 #define STOP_STARTED 2 #define SDHCI_USE_DMA 4 /* Use DMA for this req. */ +#define PLATFORM_DATA_STARTED 8 /* Data transfer is handled by platform */ struct mtx mtx; /* Slot mutex */ }; @@ -257,6 +259,8 @@ int sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t * int sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value); int sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num); void sdhci_start_slot(struct sdhci_slot *slot); +/* performs generic clean-up for platform transfers */ +void sdhci_finish_data(struct sdhci_slot *slot); int sdhci_cleanup_slot(struct sdhci_slot *slot); int sdhci_generic_suspend(struct sdhci_slot *slot); int sdhci_generic_resume(struct sdhci_slot *slot); diff --git a/sys/dev/sdhci/sdhci_if.m b/sys/dev/sdhci/sdhci_if.m index b434fd2..f0b7567 100644 --- a/sys/dev/sdhci/sdhci_if.m +++ b/sys/dev/sdhci/sdhci_if.m @@ -131,6 +131,22 @@ METHOD void write_multi_4 { bus_size_t count; } +METHOD int platform_will_handle { + device_t brdev; + struct sdhci_slot *slot; +} + +METHOD void platform_start_transfer { + device_t brdev; + struct sdhci_slot *slot; + uint32_t *intmask; +} + +METHOD void platform_finish_transfer { + device_t brdev; + struct sdhci_slot *slot; +} + METHOD uint32_t min_freq { device_t brdev; struct sdhci_slot *slot; diff --git a/sys/dev/tws/tws_hdm.c b/sys/dev/tws/tws_hdm.c index 3f6bea0..f5bb3f1 100644 --- a/sys/dev/tws/tws_hdm.c +++ b/sys/dev/tws/tws_hdm.c @@ -99,7 +99,7 @@ tws_init_ctlr(struct tws_softc *sc) regh = tws_read_reg(sc, TWS_I2O0_IOPOBQPH, 4); regl = tws_read_reg(sc, TWS_I2O0_IOPOBQPL, 4); reg = (((u_int64_t)regh) << 32) | regl; - TWS_TRACE_DEBUG(sc, "host outbound clenup",reg, regl); + TWS_TRACE_DEBUG(sc, "host outbound cleanup",reg, regl); if ( regh == TWS_FIFO_EMPTY32 ) break; } diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index eb36da1..8eca8f0 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -24,6 +24,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "opt_platform.h" + #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -35,6 +37,12 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <machine/bus.h> +#ifdef FDT +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#endif + #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> #include <dev/uart/uart_bus.h> @@ -45,6 +53,11 @@ __FBSDID("$FreeBSD$"); #define DEFAULT_RCLK 1843200 +static int broken_txfifo = 0; +SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RW | CTLFLAG_TUN, + &broken_txfifo, 0, "UART FIFO has QEMU emulation bug"); +TUNABLE_INT("hw.broken_txfifo", &broken_txfifo); + /* * Clear pending interrupts. THRE is cleared by reading IIR. Data * that may have been received gets lost here. @@ -350,6 +363,7 @@ struct ns8250_softc { uint8_t ier_mask; uint8_t ier_rxbits; + uint8_t busy_detect; }; static int ns8250_bus_attach(struct uart_softc *); @@ -401,6 +415,24 @@ ns8250_bus_attach(struct uart_softc *sc) struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; unsigned int ivar; +#ifdef FDT + phandle_t node; + pcell_t cell; +#endif + + ns8250->busy_detect = 0; + +#ifdef FDT + /* + * Check whether uart requires to read USR reg when IIR_BUSY and + * has broken txfifo. + */ + node = ofw_bus_get_node(sc->sc_dev); + if ((OF_getprop(node, "busy-detect", &cell, sizeof(cell))) > 0) + ns8250->busy_detect = 1; + if ((OF_getprop(node, "broken-txfifo", &cell, sizeof(cell))) > 0) + broken_txfifo = 1; +#endif bas = &sc->sc_bas; @@ -592,6 +624,12 @@ ns8250_bus_ipend(struct uart_softc *sc) bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); iir = uart_getreg(bas, REG_IIR); + + if (ns8250->busy_detect && (iir & IIR_BUSY) == IIR_BUSY) { + (void)uart_getreg(bas, DW_REG_USR); + uart_unlock(sc->sc_hwmtx); + return (0); + } if (iir & IIR_NOPEND) { uart_unlock(sc->sc_hwmtx); return (0); @@ -847,11 +885,6 @@ ns8250_bus_setsig(struct uart_softc *sc, int sig) return (0); } -static int broken_txfifo = 0; -SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RW | CTLFLAG_TUN, - &broken_txfifo, 0, "UART FIFO has QEMU emulation bug"); -TUNABLE_INT("hw.broken_txfifo", &broken_txfifo); - static int ns8250_bus_transmit(struct uart_softc *sc) { diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c index c3dbccf..cb5e3c0 100644 --- a/sys/fs/fdescfs/fdesc_vfsops.c +++ b/sys/fs/fdescfs/fdesc_vfsops.c @@ -205,7 +205,7 @@ fdesc_statfs(mp, sbp) last = min(fdp->fd_nfiles, lim); freefd = 0; for (i = fdp->fd_freefile; i < last; i++) - if (fdp->fd_ofiles[i] == NULL) + if (fdp->fd_ofiles[i].fde_file == NULL) freefd++; /* diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index 3c4f44d..7923fc6 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/fdesc_vnops.c @@ -534,7 +534,7 @@ fdesc_readdir(ap) dp->d_type = DT_DIR; break; default: - if (fdp->fd_ofiles[fcnt] == NULL) + if (fdp->fd_ofiles[fcnt].fde_file == NULL) break; dp->d_namlen = sprintf(dp->d_name, "%d", fcnt); dp->d_reclen = UIO_MX; diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h index 529ada2..a09a6dd 100644 --- a/sys/fs/nfs/nfsdport.h +++ b/sys/fs/nfs/nfsdport.h @@ -94,8 +94,6 @@ struct nfsexstuff { #define NFSFPCRED(f) ((f)->f_cred) #define NFSFPFLAG(f) ((f)->f_flag) -int fp_getfvp(NFSPROC_T *, int, struct file **, struct vnode **); - #define NFSNAMEICNDSET(n, c, o, f) do { \ (n)->cn_cred = (c); \ (n)->cn_nameiop = (o); \ diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 1179eb5..a07a67f 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -1215,7 +1215,7 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap) * pretend that we need them all. It is better to be too * careful than too reckless. */ - if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_ALL, &fp)) + if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_CLIENT, &fp)) != 0) { return (error); } diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 7f98201..d5cc979 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -2767,7 +2767,7 @@ out: /* * glue for fp. */ -int +static int fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp) { struct filedesc *fdp; @@ -2775,8 +2775,8 @@ fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp) int error = 0; fdp = p->td_proc->p_fd; - if (fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL) { + if (fd < 0 || fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[fd].fde_file) == NULL) { error = EBADF; goto out; } @@ -3041,7 +3041,7 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) * pretend that we need them all. It is better to be too * careful than too reckless. */ - if ((error = fget(td, sockarg.sock, CAP_SOCK_ALL, &fp)) != 0) + if ((error = fget(td, sockarg.sock, CAP_SOCK_SERVER, &fp)) != 0) goto out; if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 3724e0a..02932bd 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -313,7 +313,8 @@ nullfs_statfs(mp, sbp) /* now copy across the "interesting" information and fake the rest */ sbp->f_type = mstat.f_type; - sbp->f_flags = mstat.f_flags; + sbp->f_flags = (sbp->f_flags & (MNT_RDONLY | MNT_NOEXEC | MNT_NOSUID | + MNT_UNION | MNT_NOSYMFOLLOW)) | (mstat.f_flags & ~MNT_ROOTFS); sbp->f_bsize = mstat.f_bsize; sbp->f_iosize = mstat.f_iosize; sbp->f_blocks = mstat.f_blocks; diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 47af43b..3a98ded 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -146,7 +146,7 @@ device sa # Sequential Access (tape etc) device cd # CD device pass # Passthrough device (direct ATA/SCSI access) device ses # Enclosure Services (SES and SAF-TE) -device ctl # CAM Target Layer +#device ctl # CAM Target Layer # RAID controllers interfaced to the SCSI subsystem device amr # AMI MegaRAID diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 7a2e150..226b62b 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1221,7 +1221,7 @@ cpu_halt(void) int scheduler_running; static void -cpu_idle_hlt(int busy) +cpu_idle_hlt(sbintime_t sbt) { scheduler_running = 1; @@ -1242,7 +1242,7 @@ cpu_halt(void) #endif -void (*cpu_idle_hook)(void) = NULL; /* ACPI idle hook. */ +void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */ static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ TUNABLE_INT("machdep.idle_mwait", &idle_mwait); @@ -1254,7 +1254,7 @@ SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, #define STATE_SLEEPING 0x2 static void -cpu_idle_acpi(int busy) +cpu_idle_acpi(sbintime_t sbt) { int *state; @@ -1266,7 +1266,7 @@ cpu_idle_acpi(int busy) if (sched_runnable()) enable_intr(); else if (cpu_idle_hook) - cpu_idle_hook(); + cpu_idle_hook(sbt); else __asm __volatile("sti; hlt"); *state = STATE_RUNNING; @@ -1274,7 +1274,7 @@ cpu_idle_acpi(int busy) #ifndef XEN static void -cpu_idle_hlt(int busy) +cpu_idle_hlt(sbintime_t sbt) { int *state; @@ -1316,7 +1316,7 @@ cpu_idle_hlt(int busy) #define MWAIT_C4 0x30 static void -cpu_idle_mwait(int busy) +cpu_idle_mwait(sbintime_t sbt) { int *state; @@ -1339,7 +1339,7 @@ cpu_idle_mwait(int busy) } static void -cpu_idle_spin(int busy) +cpu_idle_spin(sbintime_t sbt) { int *state; int i; @@ -1389,9 +1389,9 @@ cpu_probe_amdc1e(void) } #ifdef XEN -void (*cpu_idle_fn)(int) = cpu_idle_hlt; +void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt; #else -void (*cpu_idle_fn)(int) = cpu_idle_acpi; +void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi; #endif void @@ -1400,6 +1400,7 @@ cpu_idle(int busy) #ifndef XEN uint64_t msr; #endif + sbintime_t sbt = -1; CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", busy, curcpu); @@ -1419,7 +1420,7 @@ cpu_idle(int busy) /* If we have time - switch timers into idle mode. */ if (!busy) { critical_enter(); - cpu_idleclock(); + sbt = cpu_idleclock(); } #ifndef XEN @@ -1432,7 +1433,7 @@ cpu_idle(int busy) #endif /* Call main idle method. */ - cpu_idle_fn(busy); + cpu_idle_fn(sbt); /* Switch timers mack into active mode. */ if (!busy) { diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 764219f..80f07a2 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -2286,7 +2286,7 @@ pmap_pv_reclaim(pmap_t locked_pmap) vm_page_dirty(m); if ((tpte & PG_A) != 0) vm_page_aflag_set(m, PGA_REFERENCED); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); if (TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); @@ -2491,9 +2491,9 @@ pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va) pv_entry_t pv; rw_assert(&pvh_global_lock, RA_WLOCKED); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (pmap == PV_PMAP(pv) && va == pv->pv_va) { - TAILQ_REMOVE(&pvh->pv_list, pv, pv_list); + TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); break; } } @@ -2521,7 +2521,7 @@ pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa) pv = pmap_pvh_remove(pvh, pmap, va); KASSERT(pv != NULL, ("pmap_pv_demote_pde: pv not found")); m = PHYS_TO_VM_PAGE(pa); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); /* Instantiate the remaining NPTEPG - 1 pv entries. */ va_last = va + NBPDR - PAGE_SIZE; do { @@ -2557,7 +2557,7 @@ pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa) pv = pmap_pvh_remove(&m->md, pmap, va); KASSERT(pv != NULL, ("pmap_pv_promote_pde: pv not found")); pvh = pa_to_pvh(pa); - TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); /* Free the remaining NPTEPG - 1 pv entries. */ va_last = va + NBPDR - PAGE_SIZE; do { @@ -2604,7 +2604,7 @@ pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t m) PMAP_LOCK_ASSERT(pmap, MA_OWNED); pv = get_pv_entry(pmap, FALSE); pv->pv_va = va; - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); } /* @@ -2620,7 +2620,7 @@ pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m) if (pv_entry_count < pv_entry_high_water && (pv = get_pv_entry(pmap, TRUE)) != NULL) { pv->pv_va = va; - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); return (TRUE); } else return (FALSE); @@ -2640,7 +2640,7 @@ pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa) (pv = get_pv_entry(pmap, TRUE)) != NULL) { pv->pv_va = va; pvh = pa_to_pvh(pa); - TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); return (TRUE); } else return (FALSE); @@ -3095,7 +3095,7 @@ small_mappings: vm_page_dirty(m); pmap_unuse_pt(pmap, pv->pv_va, &free); pmap_invalidate_page(pmap, pv->pv_va); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } @@ -3550,7 +3550,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, if (pv == NULL) pv = get_pv_entry(pmap, FALSE); pv->pv_va = va; - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); pa |= PG_MANAGED; } else if (pv != NULL) free_pv_entry(pmap, pv); @@ -4258,7 +4258,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; rw_wlock(&pvh_global_lock); - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; @@ -4269,7 +4269,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) } if (!rv && loops < 16 && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; @@ -4321,7 +4321,7 @@ pmap_pvh_wired_mappings(struct md_page *pvh, int count) rw_assert(&pvh_global_lock, RA_WLOCKED); sched_pin(); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte_quick(pmap, pv->pv_va); @@ -4448,7 +4448,7 @@ pmap_remove_pages(pmap_t pmap) if ((tpte & PG_PS) != 0) { pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE; pvh = pa_to_pvh(tpte & PG_PS_FRAME); - TAILQ_REMOVE(&pvh->pv_list, pv, pv_list); + TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); if (TAILQ_EMPTY(&pvh->pv_list)) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) if (TAILQ_EMPTY(&mt->md.pv_list)) @@ -4466,7 +4466,7 @@ pmap_remove_pages(pmap_t pmap) } } else { pmap->pm_stats.resident_count--; - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); if (TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); @@ -4536,7 +4536,7 @@ pmap_is_modified_pvh(struct md_page *pvh) rw_assert(&pvh_global_lock, RA_WLOCKED); rv = FALSE; sched_pin(); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte_quick(pmap, pv->pv_va); @@ -4609,7 +4609,7 @@ pmap_is_referenced_pvh(struct md_page *pvh) rw_assert(&pvh_global_lock, RA_WLOCKED); rv = FALSE; sched_pin(); - TAILQ_FOREACH(pv, &pvh->pv_list, pv_list) { + TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pte = pmap_pte_quick(pmap, pv->pv_va); @@ -4652,7 +4652,7 @@ pmap_remove_write(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { va = pv->pv_va; pmap = PV_PMAP(pv); PMAP_LOCK(pmap); @@ -4662,7 +4662,7 @@ pmap_remove_write(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4721,7 +4721,7 @@ pmap_ts_referenced(vm_page_t m) sched_pin(); if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, pvn) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, pvn) { va = pv->pv_va; pmap = PV_PMAP(pv); PMAP_LOCK(pmap); @@ -4755,9 +4755,9 @@ small_mappings: if ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { pvf = pv; do { - pvn = TAILQ_NEXT(pv, pv_list); - TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); - TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + pvn = TAILQ_NEXT(pv, pv_next); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4811,7 +4811,7 @@ pmap_clear_modify(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { va = pv->pv_va; pmap = PV_PMAP(pv); PMAP_LOCK(pmap); @@ -4848,7 +4848,7 @@ pmap_clear_modify(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -4892,7 +4892,7 @@ pmap_clear_reference(vm_page_t m) if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_list, next_pv) { + TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { va = pv->pv_va; pmap = PV_PMAP(pv); PMAP_LOCK(pmap); @@ -4915,7 +4915,7 @@ pmap_clear_reference(vm_page_t m) PMAP_UNLOCK(pmap); } small_mappings: - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); pde = pmap_pde(pmap, pv->pv_va); @@ -5426,7 +5426,7 @@ pmap_pvdump(vm_paddr_t pa) printf("pa %x", pa); m = PHYS_TO_VM_PAGE(pa); - TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); printf(" -> pmap %p, va %x", (void *)pmap, pv->pv_va); pads(pmap); diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c index 0692122..9f382aa 100644 --- a/sys/i386/ibcs2/ibcs2_misc.c +++ b/sys/i386/ibcs2/ibcs2_misc.c @@ -337,8 +337,7 @@ ibcs2_getdents(td, uap) #define BSD_DIRENT(cp) ((struct dirent *)(cp)) #define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short)) - if ((error = getvnode(td->td_proc->p_fd, uap->fd, - CAP_READ | CAP_SEEK, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -491,8 +490,8 @@ ibcs2_read(td, uap) u_long *cookies = NULL, *cookiep; int ncookies; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, - CAP_READ | CAP_SEEK, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, + &fp)) != 0) { if (error == EINVAL) return sys_read(td, (struct read_args *)uap); else diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h index 7a827f8..1de47f2 100644 --- a/sys/i386/include/pmap.h +++ b/sys/i386/include/pmap.h @@ -468,7 +468,7 @@ extern struct pmap kernel_pmap_store; */ typedef struct pv_entry { vm_offset_t pv_va; /* virtual address for mapping */ - TAILQ_ENTRY(pv_entry) pv_list; + TAILQ_ENTRY(pv_entry) pv_next; } *pv_entry_t; /* diff --git a/sys/i386/xen/clock.c b/sys/i386/xen/clock.c index 4e43a12..a10b546 100644 --- a/sys/i386/xen/clock.c +++ b/sys/i386/xen/clock.c @@ -768,8 +768,7 @@ resettodr() #endif static int -xen_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +xen_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct xen_et_state *state = DPCPU_PTR(et_state); struct shadow_time_info *shadow; @@ -777,21 +776,16 @@ xen_et_start(struct eventtimer *et, __get_time_values_from_xen(); - if (period != NULL) { + if (period != 0) { state->mode = MODE_PERIODIC; - state->period = (1000000000LL * - (uint32_t)(period->frac >> 32)) >> 32; - if (period->sec != 0) - state->period += 1000000000LL * period->sec; + state->period = (1000000000LLU * period) >> 32; } else { state->mode = MODE_ONESHOT; state->period = 0; } - if (first != NULL) { - fperiod = (1000000000LL * (uint32_t)(first->frac >> 32)) >> 32; - if (first->sec != 0) - fperiod += 1000000000LL * first->sec; - } else + if (first != 0) + fperiod = (1000000000LLU * first) >> 32; + else fperiod = state->period; shadow = &per_cpu(shadow_time, smp_processor_id()); @@ -832,11 +826,9 @@ cpu_initclocks(void) xen_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; xen_et.et_quality = 600; - xen_et.et_frequency = 0; - xen_et.et_min_period.sec = 0; - xen_et.et_min_period.frac = 0x00400000LL << 32; - xen_et.et_max_period.sec = 2; - xen_et.et_max_period.frac = 0; + xen_et.et_frequency = 1000000000; + xen_et.et_min_period = 0x00400000LL; + xen_et.et_max_period = (0xfffffffeLLU << 32) / xen_et.et_frequency; xen_et.et_start = xen_et_start; xen_et.et_stop = xen_et_stop; xen_et.et_priv = NULL; diff --git a/sys/ia64/ia64/clock.c b/sys/ia64/ia64/clock.c index 24623c5..37a99a1 100644 --- a/sys/ia64/ia64/clock.c +++ b/sys/ia64/ia64/clock.c @@ -105,17 +105,14 @@ ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf) * Event timer start method. */ static int -ia64_clock_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +ia64_clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { u_long itc, load; register_t is; - if (period != NULL) { + if (period != 0) { PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC); - load = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec > 0) - load += et->et_frequency * period->sec; + load = (et->et_frequency * period) >> 32; } else { PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT); load = 0; @@ -123,11 +120,8 @@ ia64_clock_start(struct eventtimer *et, struct bintime *first, PCPU_SET(md.clock_load, load); - if (first != NULL) { - load = (et->et_frequency * (first->frac >> 32)) >> 32; - if (first->sec > 0) - load += et->et_frequency * first->sec; - } + if (first != 0) + load = (et->et_frequency * first) >> 32; is = intr_disable(); itc = ia64_get_itc(); @@ -185,10 +179,8 @@ clock_configure(void *dummy) et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; et->et_quality = 1000; et->et_frequency = itc_freq; - et->et_min_period.sec = 0; - et->et_min_period.frac = (0x8000000000000000ul / (u_long)(10*hz)) << 1; - et->et_max_period.sec = 0xffffffff; - et->et_max_period.frac = ((0xfffffffeul << 32) / itc_freq) << 32; + et->et_min_period = SBT_1S / (10 * hz); + et->et_max_period = (0xfffffffeul << 32) / itc_freq; et->et_start = ia64_clock_start; et->et_stop = ia64_clock_stop; et->et_priv = NULL; diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index 2bc4a65..5373151 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -172,7 +172,7 @@ extern vm_offset_t ksym_start, ksym_end; struct msgbuf *msgbufp = NULL; /* Other subsystems (e.g., ACPI) can hook this later. */ -void (*cpu_idle_hook)(void) = NULL; +void (*cpu_idle_hook)(sbintime_t) = NULL; struct kva_md_info kmi; @@ -409,10 +409,11 @@ void cpu_idle(int busy) { register_t ie; + sbintime_t sbt = -1; if (!busy) { critical_enter(); - cpu_idleclock(); + sbt = cpu_idleclock(); } ie = intr_disable(); @@ -421,7 +422,7 @@ cpu_idle(int busy) if (sched_runnable()) ia64_enable_intr(); else if (cpu_idle_hook != NULL) { - (*cpu_idle_hook)(); + (*cpu_idle_hook)(sbt); /* The hook must enable interrupts! */ } else { ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0); diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf index 11aad16..3c08782 100644 --- a/sys/kern/capabilities.conf +++ b/sys/kern/capabilities.conf @@ -110,9 +110,14 @@ aio_write ## Allow capability mode and capability system calls. ## cap_enter +cap_fcntls_get +cap_fcntls_limit cap_getmode -cap_getrights +cap_ioctls_get +cap_ioctls_limit cap_new +cap_rights_get +cap_rights_limit ## ## Allow read-only clock operations. @@ -239,7 +244,7 @@ getcontext ## Allow directory I/O on a file descriptor, subject to capability rights. ## Originally we had separate capabilities for directory-specific read ## operations, but on BSD we allow reading the raw directory data, so we just -## rely on CAP_READ and CAP_SEEK now. +## rely on CAP_READ now. ## getdents getdirentries @@ -317,13 +322,10 @@ gettimeofday getuid ## -## Disallow ioctl(2) for now, as frequently ioctl(2) operations have global -## scope, but this is a tricky one as it is also required for tty control. -## We do have a capability right for this operation. +## Allow ioctl(2), which hopefully will be limited by applications only to +## required commands with cap_ioctls_limit(2) syscall. ## -## XXXRW: This needs to be revisited. -## -#ioctl +ioctl ## ## Allow querying current process credential state. diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index ce47f56..b5ed57b 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #include "opt_compat.h" @@ -88,7 +88,7 @@ struct sysent sysent[] = { { AS(acct_args), (sy_call_t *)sys_acct, AUE_ACCT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 51 = acct */ { compat(0,sigpending), AUE_SIGPENDING, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 52 = old sigpending */ { AS(sigaltstack_args), (sy_call_t *)sys_sigaltstack, AUE_SIGALTSTACK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 53 = sigaltstack */ - { AS(ioctl_args), (sy_call_t *)sys_ioctl, AUE_IOCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = ioctl */ + { AS(ioctl_args), (sy_call_t *)sys_ioctl, AUE_IOCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 54 = ioctl */ { AS(reboot_args), (sy_call_t *)sys_reboot, AUE_REBOOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 55 = reboot */ { AS(revoke_args), (sy_call_t *)sys_revoke, AUE_REVOKE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 56 = revoke */ { AS(symlink_args), (sy_call_t *)sys_symlink, AUE_SYMLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = symlink */ @@ -549,7 +549,7 @@ struct sysent sysent[] = { { AS(shmctl_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 512 = shmctl */ { AS(lpathconf_args), (sy_call_t *)sys_lpathconf, AUE_LPATHCONF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 513 = lpathconf */ { AS(cap_new_args), (sy_call_t *)sys_cap_new, AUE_CAP_NEW, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 514 = cap_new */ - { AS(cap_getrights_args), (sy_call_t *)sys_cap_getrights, AUE_CAP_GETRIGHTS, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 515 = cap_getrights */ + { AS(cap_rights_get_args), (sy_call_t *)sys_cap_rights_get, AUE_CAP_RIGHTS_GET, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 515 = cap_rights_get */ { 0, (sy_call_t *)sys_cap_enter, AUE_CAP_ENTER, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 516 = cap_enter */ { AS(cap_getmode_args), (sy_call_t *)sys_cap_getmode, AUE_CAP_GETMODE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 517 = cap_getmode */ { AS(pdfork_args), (sy_call_t *)sys_pdfork, AUE_PDFORK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 518 = pdfork */ @@ -567,4 +567,9 @@ struct sysent sysent[] = { { AS(posix_fallocate_args), (sy_call_t *)sys_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = posix_fallocate */ { AS(posix_fadvise_args), (sy_call_t *)sys_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = posix_fadvise */ { AS(wait6_args), (sy_call_t *)sys_wait6, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = wait6 */ + { AS(cap_rights_limit_args), (sy_call_t *)sys_cap_rights_limit, AUE_CAP_RIGHTS_LIMIT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 533 = cap_rights_limit */ + { AS(cap_ioctls_limit_args), (sy_call_t *)sys_cap_ioctls_limit, AUE_CAP_IOCTLS_LIMIT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 534 = cap_ioctls_limit */ + { AS(cap_ioctls_get_args), (sy_call_t *)sys_cap_ioctls_get, AUE_CAP_IOCTLS_GET, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 535 = cap_ioctls_get */ + { AS(cap_fcntls_limit_args), (sy_call_t *)sys_cap_fcntls_limit, AUE_CAP_FCNTLS_LIMIT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 536 = cap_fcntls_limit */ + { AS(cap_fcntls_get_args), (sy_call_t *)sys_cap_fcntls_get, AUE_CAP_FCNTLS_GET, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 537 = cap_fcntls_get */ }; diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c index 33f21e9..10732d9 100644 --- a/sys/kern/kern_clocksource.c +++ b/sys/kern/kern_clocksource.c @@ -153,6 +153,8 @@ static DPCPU_DEFINE(struct pcpu_state, timerstate); (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ ((bt)->frac >> 1)) +#define SBT2FREQ(sbt) ((SBT_1S + ((sbt) >> 1)) / (sbt)) + /* * Timer broadcast IPI handler. */ @@ -442,7 +444,7 @@ loadtimer(struct bintime *now, int start) new.sec, (u_int)(new.frac >> 32)); *next = new; bintime_add(next, now); - et_start(timer, &new, &timerperiod); + et_start(timer, bttosbt(new), bttosbt(timerperiod)); } } else { getnextevent(&new); @@ -454,7 +456,7 @@ loadtimer(struct bintime *now, int start) if (!eq) { *next = new; bintime_sub(&new, now); - et_start(timer, &new, NULL); + et_start(timer, bttosbt(new), 0); } } } @@ -603,13 +605,13 @@ round_freq(struct eventtimer *et, int freq) div = 1 << (flsl(div + div / 2) - 1); freq = (et->et_frequency + div / 2) / div; } - if (et->et_min_period.sec > 0) + if (et->et_min_period > SBT_1S) panic("Event timer \"%s\" doesn't support sub-second periods!", et->et_name); - else if (et->et_min_period.frac != 0) - freq = min(freq, BT2FREQ(&et->et_min_period)); - if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0) - freq = max(freq, BT2FREQ(&et->et_max_period)); + else if (et->et_min_period != 0) + freq = min(freq, SBT2FREQ(et->et_min_period)); + if (et->et_max_period < SBT_1S && et->et_max_period != 0) + freq = max(freq, SBT2FREQ(et->et_max_period)); return (freq); } @@ -767,7 +769,7 @@ cpu_stopprofclock(void) /* * Switch to idle mode (all ticks handled). */ -void +sbintime_t cpu_idleclock(void) { struct bintime now, t; @@ -779,7 +781,7 @@ cpu_idleclock(void) || curcpu == CPU_FIRST() #endif ) - return; + return (-1); state = DPCPU_PTR(timerstate); if (periodic) now = state->now; @@ -795,6 +797,8 @@ cpu_idleclock(void) if (!periodic) loadtimer(&now, 0); ET_HW_UNLOCK(state); + bintime_sub(&t, &now); + return (MAX(bttosbt(t), 0)); } /* diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index acdea40..b146bab 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -110,15 +110,8 @@ MALLOC_DECLARE(M_FADVISE); static uma_zone_t file_zone; -/* Flags for do_dup() */ -#define DUP_FIXED 0x1 /* Force fixed allocation */ -#define DUP_FCNTL 0x2 /* fcntl()-style errors */ -#define DUP_CLOEXEC 0x4 /* Atomically set FD_CLOEXEC. */ - static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders); -static int do_dup(struct thread *td, int flags, int old, int new, - register_t *retval); static int fd_first_free(struct filedesc *fdp, int low, int size); static int fd_last_used(struct filedesc *fdp, int size); static void fdgrowtable(struct filedesc *fdp, int nfd); @@ -166,7 +159,7 @@ static int fill_vnode_info(struct vnode *vp, struct kinfo_file *kif); * the process exits. */ struct freetable { - struct file **ft_table; + struct filedescent *ft_table; SLIST_ENTRY(freetable) ft_next; }; @@ -177,8 +170,7 @@ struct freetable { struct filedesc0 { struct filedesc fd_fd; SLIST_HEAD(, freetable) fd_free; - struct file *fd_dfiles[NDFILE]; - char fd_dfileflags[NDFILE]; + struct filedescent fd_dfiles[NDFILE]; NDSLOTTYPE fd_dmap[NDSLOTS(NDFILE)]; }; @@ -284,7 +276,8 @@ fdunused(struct filedesc *fdp, int fd) FILEDESC_XLOCK_ASSERT(fdp); KASSERT(fdisused(fdp, fd), ("fd=%d is already unused", fd)); - KASSERT(fdp->fd_ofiles[fd] == NULL, ("fd=%d is still in use", fd)); + KASSERT(fdp->fd_ofiles[fd].fde_file == NULL, + ("fd=%d is still in use", fd)); fdp->fd_map[NDSLOT(fd)] &= ~NDBIT(fd); if (fd < fdp->fd_freefile) @@ -294,6 +287,20 @@ fdunused(struct filedesc *fdp, int fd) } /* + * Free a file descriptor. + */ +static inline void +fdfree(struct filedesc *fdp, int fd) +{ + struct filedescent *fde; + + fde = &fdp->fd_ofiles[fd]; + filecaps_free(&fde->fde_caps); + bzero(fde, sizeof(*fde)); + fdunused(fdp, fd); +} + +/* * System calls on descriptors. */ #ifndef _SYS_SYSPROTO_H_ @@ -434,36 +441,14 @@ sys_fcntl(struct thread *td, struct fcntl_args *uap) return (error); } -static inline int -fdunwrap(int fd, cap_rights_t rights, struct filedesc *fdp, struct file **fpp) -{ - - FILEDESC_LOCK_ASSERT(fdp); - - *fpp = fget_locked(fdp, fd); - if (*fpp == NULL) - return (EBADF); - -#ifdef CAPABILITIES - if ((*fpp)->f_type == DTYPE_CAPABILITY) { - int err = cap_funwrap(*fpp, rights, fpp); - if (err != 0) { - *fpp = NULL; - return (err); - } - } -#endif /* CAPABILITIES */ - return (0); -} - int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) { struct filedesc *fdp; struct flock *flp; - struct file *fp; + struct file *fp, *fp2; + struct filedescent *fde; struct proc *p; - char *pop; struct vnode *vp; int error, flg, tmp; u_int old, new; @@ -505,8 +490,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = EBADF; break; } - pop = &fdp->fd_ofileflags[fd]; - td->td_retval[0] = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0; + fde = &fdp->fd_ofiles[fd]; + td->td_retval[0] = + (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0; FILEDESC_SUNLOCK(fdp); break; @@ -517,32 +503,24 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = EBADF; break; } - pop = &fdp->fd_ofileflags[fd]; - *pop = (*pop &~ UF_EXCLOSE) | + fde = &fdp->fd_ofiles[fd]; + fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | (arg & FD_CLOEXEC ? UF_EXCLOSE : 0); FILEDESC_XUNLOCK(fdp); break; case F_GETFL: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETFL, &fp, NULL); + if (error != 0) break; - } td->td_retval[0] = OFLAGS(fp->f_flag); - FILEDESC_SUNLOCK(fdp); + fdrop(fp, td); break; case F_SETFL: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETFL, &fp, NULL); + if (error != 0) break; - } - fhold(fp); - FILEDESC_SUNLOCK(fdp); do { tmp = flg = fp->f_flag; tmp &= ~FCNTLFLAGS; @@ -550,7 +528,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) } while(atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0); tmp = fp->f_flag & FNONBLOCK; error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); - if (error) { + if (error != 0) { fdrop(fp, td); break; } @@ -567,14 +545,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_GETOWN: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETOWN, &fp, NULL); + if (error != 0) break; - } - fhold(fp); - FILEDESC_SUNLOCK(fdp); error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td); if (error == 0) td->td_retval[0] = tmp; @@ -582,14 +555,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_SETOWN: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETOWN, &fp, NULL); + if (error != 0) break; - } - fhold(fp); - FILEDESC_SUNLOCK(fdp); tmp = arg; error = fo_ioctl(fp, FIOSETOWN, &tmp, td->td_ucred, td); fdrop(fp, td); @@ -608,17 +576,15 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETLK: do_setlk: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FLOCK, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL); + if (error != 0) break; - } if (fp->f_type != DTYPE_VNODE) { - FILEDESC_SUNLOCK(fdp); error = EBADF; + fdrop(fp, td); break; } + flp = (struct flock *)arg; if (flp->l_whence == SEEK_CUR) { foffset = foffset_get(fp); @@ -627,16 +593,12 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) foffset > OFF_MAX - flp->l_start)) { FILEDESC_SUNLOCK(fdp); error = EOVERFLOW; + fdrop(fp, td); break; } flp->l_start += foffset; } - /* - * VOP_ADVLOCK() may block. - */ - fhold(fp); - FILEDESC_SUNLOCK(fdp); vp = fp->f_vnode; switch (flp->l_type) { case F_RDLCK: @@ -703,37 +665,37 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) * that the closing thread was a bit slower and that the * advisory lock succeeded before the close. */ - FILEDESC_SLOCK(fdp); - if (fget_locked(fdp, fd) != fp) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, 0, 0, &fp2, NULL); + if (error != 0) { + fdrop(fp, td); + break; + } + if (fp != fp2) { flp->l_whence = SEEK_SET; flp->l_start = 0; flp->l_len = 0; flp->l_type = F_UNLCK; (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, flp, F_POSIX); - } else - FILEDESC_SUNLOCK(fdp); + } fdrop(fp, td); + fdrop(fp2, td); break; case F_GETLK: - FILEDESC_SLOCK(fdp); - error = fdunwrap(fd, CAP_FLOCK, fdp, &fp); - if (error != 0) { - FILEDESC_SUNLOCK(fdp); + error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL); + if (error != 0) break; - } if (fp->f_type != DTYPE_VNODE) { - FILEDESC_SUNLOCK(fdp); error = EBADF; + fdrop(fp, td); break; } flp = (struct flock *)arg; if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK && flp->l_type != F_UNLCK) { - FILEDESC_SUNLOCK(fdp); error = EINVAL; + fdrop(fp, td); break; } if (flp->l_whence == SEEK_CUR) { @@ -744,15 +706,11 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) foffset < OFF_MIN - flp->l_start)) { FILEDESC_SUNLOCK(fdp); error = EOVERFLOW; + fdrop(fp, td); break; } flp->l_start += foffset; } - /* - * VOP_ADVLOCK() may block. - */ - fhold(fp); - FILEDESC_SUNLOCK(fdp); vp = fp->f_vnode; error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp, F_POSIX); @@ -763,19 +721,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) arg = arg ? 128 * 1024: 0; /* FALLTHROUGH */ case F_READAHEAD: - FILEDESC_SLOCK(fdp); - if ((fp = fget_locked(fdp, fd)) == NULL) { - FILEDESC_SUNLOCK(fdp); - error = EBADF; + error = fget_unlocked(fdp, fd, 0, 0, &fp, NULL); + if (error != 0) break; - } if (fp->f_type != DTYPE_VNODE) { - FILEDESC_SUNLOCK(fdp); + fdrop(fp, td); error = EBADF; break; } - fhold(fp); - FILEDESC_SUNLOCK(fdp); if (arg >= 0) { vp = fp->f_vnode; error = vn_lock(vp, LK_SHARED); @@ -809,11 +762,12 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) /* * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). */ -static int +int do_dup(struct thread *td, int flags, int old, int new, register_t *retval) { struct filedesc *fdp; + struct filedescent *oldfde, *newfde; struct proc *p; struct file *fp; struct file *delfp; @@ -842,14 +796,15 @@ do_dup(struct thread *td, int flags, int old, int new, FILEDESC_XUNLOCK(fdp); return (EBADF); } + oldfde = &fdp->fd_ofiles[old]; if (flags & DUP_FIXED && old == new) { *retval = new; if (flags & DUP_CLOEXEC) - fdp->fd_ofileflags[new] |= UF_EXCLOSE; + fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); return (0); } - fp = fdp->fd_ofiles[old]; + fp = oldfde->fde_file; fhold(fp); /* @@ -878,8 +833,10 @@ do_dup(struct thread *td, int flags, int old, int new, } #endif fdgrowtable(fdp, new + 1); + oldfde = &fdp->fd_ofiles[old]; } - if (fdp->fd_ofiles[new] == NULL) + newfde = &fdp->fd_ofiles[new]; + if (newfde->fde_file == NULL) fdused(fdp, new); } else { if ((error = fdalloc(td, new, &new)) != 0) { @@ -887,20 +844,23 @@ do_dup(struct thread *td, int flags, int old, int new, fdrop(fp, td); return (error); } + newfde = &fdp->fd_ofiles[new]; } - KASSERT(fp == fdp->fd_ofiles[old], ("old fd has been modified")); + KASSERT(fp == oldfde->fde_file, ("old fd has been modified")); KASSERT(old != new, ("new fd is same as old")); - delfp = fdp->fd_ofiles[new]; + delfp = newfde->fde_file; + /* * Duplicate the source descriptor. */ - fdp->fd_ofiles[new] = fp; + *newfde = *oldfde; + filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps); if ((flags & DUP_CLOEXEC) != 0) - fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] | UF_EXCLOSE; + newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE; else - fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE; + newfde->fde_flags = oldfde->fde_flags & ~UF_EXCLOSE; if (new > fdp->fd_lastfile) fdp->fd_lastfile = new; *retval = new; @@ -1141,7 +1101,6 @@ static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders) { - struct file *fp_object; int error; FILEDESC_XLOCK_ASSERT(fdp); @@ -1167,12 +1126,10 @@ closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, knote_fdclose(td, fd); /* - * When we're closing an fd with a capability, we need to notify - * mqueue if the underlying object is of type mqueue. + * We need to notify mqueue if the object is of type mqueue. */ - (void)cap_funwrap(fp, 0, &fp_object); - if (fp_object->f_type == DTYPE_MQUEUE) - mq_fdclose(td, fd, fp_object); + if (fp->f_type == DTYPE_MQUEUE) + mq_fdclose(td, fd, fp); FILEDESC_XUNLOCK(fdp); error = closef(fp, td); @@ -1224,9 +1181,7 @@ kern_close(td, fd) FILEDESC_XUNLOCK(fdp); return (EBADF); } - fdp->fd_ofiles[fd] = NULL; - fdp->fd_ofileflags[fd] = 0; - fdunused(fdp, fd); + fdfree(fdp, fd); /* closefp() drops the FILEDESC lock for us. */ return (closefp(fdp, fd, fp, td, 1)); @@ -1258,7 +1213,7 @@ sys_closefrom(struct thread *td, struct closefrom_args *uap) uap->lowfd = 0; FILEDESC_SLOCK(fdp); for (fd = uap->lowfd; fd < fdp->fd_nfiles; fd++) { - if (fdp->fd_ofiles[fd] != NULL) { + if (fdp->fd_ofiles[fd].fde_file != NULL) { FILEDESC_SUNLOCK(fdp); (void)kern_close(td, fd); FILEDESC_SLOCK(fdp); @@ -1410,6 +1365,91 @@ out: } /* + * Initialize filecaps structure. + */ +void +filecaps_init(struct filecaps *fcaps) +{ + + bzero(fcaps, sizeof(*fcaps)); + fcaps->fc_nioctls = -1; +} + +/* + * Copy filecaps structure allocating memory for ioctls array if needed. + */ +void +filecaps_copy(const struct filecaps *src, struct filecaps *dst) +{ + size_t size; + + *dst = *src; + if (src->fc_ioctls != NULL) { + KASSERT(src->fc_nioctls > 0, + ("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls)); + + size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls; + dst->fc_ioctls = malloc(size, M_TEMP, M_WAITOK); + bcopy(src->fc_ioctls, dst->fc_ioctls, size); + } +} + +/* + * Move filecaps structure to the new place and clear the old place. + */ +static void +filecaps_move(struct filecaps *src, struct filecaps *dst) +{ + + *dst = *src; + bzero(src, sizeof(*src)); +} + +/* + * Fill the given filecaps structure with full rights. + */ +static void +filecaps_fill(struct filecaps *fcaps) +{ + + fcaps->fc_rights = CAP_ALL; + fcaps->fc_ioctls = NULL; + fcaps->fc_nioctls = -1; + fcaps->fc_fcntls = CAP_FCNTL_ALL; +} + +/* + * Free memory allocated within filecaps structure. + */ +void +filecaps_free(struct filecaps *fcaps) +{ + + free(fcaps->fc_ioctls, M_TEMP); + bzero(fcaps, sizeof(*fcaps)); +} + +/* + * Validate the given filecaps structure. + */ +static void +filecaps_validate(const struct filecaps *fcaps, const char *func) +{ + + KASSERT((fcaps->fc_rights & ~CAP_MASK_VALID) == 0, + ("%s: invalid rights", func)); + KASSERT((fcaps->fc_fcntls & ~CAP_FCNTL_ALL) == 0, + ("%s: invalid fcntls", func)); + KASSERT(fcaps->fc_fcntls == 0 || (fcaps->fc_rights & CAP_FCNTL) != 0, + ("%s: fcntls without CAP_FCNTL", func)); + KASSERT(fcaps->fc_ioctls != NULL ? fcaps->fc_nioctls > 0 : + (fcaps->fc_nioctls == -1 || fcaps->fc_nioctls == 0), + ("%s: invalid ioctls", func)); + KASSERT(fcaps->fc_nioctls == 0 || (fcaps->fc_rights & CAP_IOCTL) != 0, + ("%s: ioctls without CAP_IOCTL", func)); +} + +/* * Grow the file table to accomodate (at least) nfd descriptors. */ static void @@ -1417,9 +1457,8 @@ fdgrowtable(struct filedesc *fdp, int nfd) { struct filedesc0 *fdp0; struct freetable *ft; - struct file **ntable; - struct file **otable; - char *nfileflags, *ofileflags; + struct filedescent *ntable; + struct filedescent *otable; int nnfiles, onfiles; NDSLOTTYPE *nmap, *omap; @@ -1430,7 +1469,6 @@ fdgrowtable(struct filedesc *fdp, int nfd) /* save old values */ onfiles = fdp->fd_nfiles; otable = fdp->fd_ofiles; - ofileflags = fdp->fd_ofileflags; omap = fdp->fd_map; /* compute the size of the new table */ @@ -1440,27 +1478,25 @@ fdgrowtable(struct filedesc *fdp, int nfd) return; /* - * Allocate a new table and map. We need enough space for a) the - * file entries themselves, b) the file flags, and c) the struct - * freetable we will use when we decommission the table and place - * it on the freelist. We place the struct freetable in the - * middle so we don't have to worry about padding. + * Allocate a new table and map. We need enough space for the + * file entries themselves and the struct freetable we will use + * when we decommission the table and place it on the freelist. + * We place the struct freetable in the middle so we don't have + * to worry about padding. */ - ntable = malloc(nnfiles * sizeof(*ntable) + sizeof(struct freetable) + - nnfiles * sizeof(*nfileflags), M_FILEDESC, M_ZERO | M_WAITOK); - nfileflags = (char *)&ntable[nnfiles] + sizeof(struct freetable); + ntable = malloc(nnfiles * sizeof(ntable[0]) + sizeof(struct freetable), + M_FILEDESC, M_ZERO | M_WAITOK); nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC, M_ZERO | M_WAITOK); /* copy the old data over and point at the new tables */ memcpy(ntable, otable, onfiles * sizeof(*otable)); - memcpy(nfileflags, ofileflags, onfiles * sizeof(*ofileflags)); memcpy(nmap, omap, NDSLOTS(onfiles) * sizeof(*omap)); /* update the pointers and counters */ fdp->fd_nfiles = nnfiles; + memcpy(ntable, otable, onfiles * sizeof(ntable[0])); fdp->fd_ofiles = ntable; - fdp->fd_ofileflags = nfileflags; fdp->fd_map = nmap; /* @@ -1536,8 +1572,9 @@ fdalloc(struct thread *td, int minfd, int *result) ("invalid descriptor %d", fd)); KASSERT(!fdisused(fdp, fd), ("fd_first_free() returned non-free descriptor")); - KASSERT(fdp->fd_ofiles[fd] == NULL, ("file descriptor isn't free")); - KASSERT(fdp->fd_ofileflags[fd] == 0, ("file flags are set")); + KASSERT(fdp->fd_ofiles[fd].fde_file == NULL, + ("file descriptor isn't free")); + KASSERT(fdp->fd_ofiles[fd].fde_flags == 0, ("file flags are set")); fdused(fdp, fd); *result = fd; return (0); @@ -1568,7 +1605,7 @@ fdavail(struct thread *td, int n) return (1); last = min(fdp->fd_nfiles, lim); for (i = fdp->fd_freefile; i < last; i++) { - if (fdp->fd_ofiles[i] == NULL && --n <= 0) + if (fdp->fd_ofiles[i].fde_file == NULL && --n <= 0) return (1); } return (0); @@ -1591,7 +1628,7 @@ falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags) if (error) return (error); /* no reference held on error */ - error = finstall(td, fp, &fd, flags); + error = finstall(td, fp, &fd, flags, NULL); if (error) { fdrop(fp, td); /* one reference (fp only) */ return (error); @@ -1645,13 +1682,17 @@ falloc_noinstall(struct thread *td, struct file **resultfp) * Install a file in a file descriptor table. */ int -finstall(struct thread *td, struct file *fp, int *fd, int flags) +finstall(struct thread *td, struct file *fp, int *fd, int flags, + struct filecaps *fcaps) { struct filedesc *fdp = td->td_proc->p_fd; + struct filedescent *fde; int error; KASSERT(fd != NULL, ("%s: fd == NULL", __func__)); KASSERT(fp != NULL, ("%s: fp == NULL", __func__)); + if (fcaps != NULL) + filecaps_validate(fcaps, __func__); FILEDESC_XLOCK(fdp); if ((error = fdalloc(td, 0, fd))) { @@ -1659,9 +1700,14 @@ finstall(struct thread *td, struct file *fp, int *fd, int flags) return (error); } fhold(fp); - fdp->fd_ofiles[*fd] = fp; + fde = &fdp->fd_ofiles[*fd]; + fde->fde_file = fp; if ((flags & O_CLOEXEC) != 0) - fdp->fd_ofileflags[*fd] |= UF_EXCLOSE; + fde->fde_flags |= UF_EXCLOSE; + if (fcaps != NULL) + filecaps_move(fcaps, &fde->fde_caps); + else + filecaps_fill(&fde->fde_caps); FILEDESC_XUNLOCK(fdp); return (0); } @@ -1696,7 +1742,6 @@ fdinit(struct filedesc *fdp) newfdp->fd_fd.fd_holdcnt = 1; newfdp->fd_fd.fd_cmask = CMASK; newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles; - newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags; newfdp->fd_fd.fd_nfiles = NDFILE; newfdp->fd_fd.fd_map = newfdp->fd_dmap; newfdp->fd_fd.fd_lastfile = -1; @@ -1764,7 +1809,7 @@ fdunshare(struct proc *p, struct thread *td) FILEDESC_XUNLOCK(p->p_fd); tmp = fdcopy(p->p_fd); - fdfree(td); + fdescfree(td); p->p_fd = tmp; } else FILEDESC_XUNLOCK(p->p_fd); @@ -1778,6 +1823,7 @@ struct filedesc * fdcopy(struct filedesc *fdp) { struct filedesc *newfdp; + struct filedescent *nfde, *ofde; int i; /* Certain daemons might not have file descriptors. */ @@ -1796,12 +1842,14 @@ fdcopy(struct filedesc *fdp) /* copy all passable descriptors (i.e. not kqueue) */ newfdp->fd_freefile = -1; for (i = 0; i <= fdp->fd_lastfile; ++i) { + ofde = &fdp->fd_ofiles[i]; if (fdisused(fdp, i) && - (fdp->fd_ofiles[i]->f_ops->fo_flags & DFLAG_PASSABLE) && - fdp->fd_ofiles[i]->f_ops != &badfileops) { - newfdp->fd_ofiles[i] = fdp->fd_ofiles[i]; - newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i]; - fhold(newfdp->fd_ofiles[i]); + (ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) && + ofde->fde_file->f_ops != &badfileops) { + nfde = &newfdp->fd_ofiles[i]; + *nfde = *ofde; + filecaps_copy(&ofde->fde_caps, &nfde->fde_caps); + fhold(nfde->fde_file); newfdp->fd_lastfile = i; } else { if (newfdp->fd_freefile == -1) @@ -1811,9 +1859,10 @@ fdcopy(struct filedesc *fdp) newfdp->fd_cmask = fdp->fd_cmask; FILEDESC_SUNLOCK(fdp); FILEDESC_XLOCK(newfdp); - for (i = 0; i <= newfdp->fd_lastfile; ++i) - if (newfdp->fd_ofiles[i] != NULL) + for (i = 0; i <= newfdp->fd_lastfile; ++i) { + if (newfdp->fd_ofiles[i].fde_file != NULL) fdused(newfdp, i); + } if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; FILEDESC_XUNLOCK(newfdp); @@ -1824,7 +1873,7 @@ fdcopy(struct filedesc *fdp) * Release a filedesc structure. */ void -fdfree(struct thread *td) +fdescfree(struct thread *td) { struct filedesc *fdp; int i; @@ -1849,12 +1898,12 @@ fdfree(struct thread *td) if (fdtol != NULL) { FILEDESC_XLOCK(fdp); KASSERT(fdtol->fdl_refcount > 0, - ("filedesc_to_refcount botch: fdl_refcount=%d", - fdtol->fdl_refcount)); + ("filedesc_to_refcount botch: fdl_refcount=%d", + fdtol->fdl_refcount)); if (fdtol->fdl_refcount == 1 && (td->td_proc->p_leader->p_flag & P_ADVLOCK) != 0) { for (i = 0; i <= fdp->fd_lastfile; i++) { - fp = fdp->fd_ofiles[i]; + fp = fdp->fd_ofiles[i].fde_file; if (fp == NULL || fp->f_type != DTYPE_VNODE) continue; fhold(fp); @@ -1914,10 +1963,10 @@ fdfree(struct thread *td) return; for (i = 0; i <= fdp->fd_lastfile; i++) { - fp = fdp->fd_ofiles[i]; + fp = fdp->fd_ofiles[i].fde_file; if (fp != NULL) { FILEDESC_XLOCK(fdp); - fdp->fd_ofiles[i] = NULL; + fdfree(fdp, i); FILEDESC_XUNLOCK(fdp); (void) closef(fp, td); } @@ -1982,6 +2031,7 @@ void setugidsafety(struct thread *td) { struct filedesc *fdp; + struct file *fp; int i; /* Certain daemons might not have file descriptors. */ @@ -1997,18 +2047,14 @@ setugidsafety(struct thread *td) for (i = 0; i <= fdp->fd_lastfile; i++) { if (i > 2) break; - if (fdp->fd_ofiles[i] && is_unsafe(fdp->fd_ofiles[i])) { - struct file *fp; - + fp = fdp->fd_ofiles[i].fde_file; + if (fp != NULL && is_unsafe(fp)) { knote_fdclose(td, i); /* * NULL-out descriptor prior to close to avoid * a race while close blocks. */ - fp = fdp->fd_ofiles[i]; - fdp->fd_ofiles[i] = NULL; - fdp->fd_ofileflags[i] = 0; - fdunused(fdp, i); + fdfree(fdp, i); FILEDESC_XUNLOCK(fdp); (void) closef(fp, td); FILEDESC_XLOCK(fdp); @@ -2029,9 +2075,8 @@ fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td) { FILEDESC_XLOCK(fdp); - if (fdp->fd_ofiles[idx] == fp) { - fdp->fd_ofiles[idx] = NULL; - fdunused(fdp, idx); + if (fdp->fd_ofiles[idx].fde_file == fp) { + fdfree(fdp, idx); FILEDESC_XUNLOCK(fdp); fdrop(fp, td); } else @@ -2045,6 +2090,7 @@ void fdcloseexec(struct thread *td) { struct filedesc *fdp; + struct filedescent *fde; struct file *fp; int i; @@ -2054,17 +2100,16 @@ fdcloseexec(struct thread *td) return; /* - * We cannot cache fd_ofiles or fd_ofileflags since operations + * We cannot cache fd_ofiles since operations * may block and rip them out from under us. */ FILEDESC_XLOCK(fdp); for (i = 0; i <= fdp->fd_lastfile; i++) { - fp = fdp->fd_ofiles[i]; + fde = &fdp->fd_ofiles[i]; + fp = fde->fde_file; if (fp != NULL && (fp->f_type == DTYPE_MQUEUE || - (fdp->fd_ofileflags[i] & UF_EXCLOSE))) { - fdp->fd_ofiles[i] = NULL; - fdp->fd_ofileflags[i] = 0; - fdunused(fdp, i); + (fde->fde_flags & UF_EXCLOSE))) { + fdfree(fdp, i); (void) closefp(fdp, i, fp, td, 0); /* closefp() drops the FILEDESC lock. */ FILEDESC_XLOCK(fdp); @@ -2094,7 +2139,7 @@ fdcheckstd(struct thread *td) devnull = -1; error = 0; for (i = 0; i < 3; i++) { - if (fdp->fd_ofiles[i] != NULL) + if (fdp->fd_ofiles[i].fde_file != NULL) continue; if (devnull < 0) { save = td->td_retval[0]; @@ -2129,7 +2174,6 @@ closef(struct file *fp, struct thread *td) struct flock lf; struct filedesc_to_leader *fdtol; struct filedesc *fdp; - struct file *fp_object; /* * POSIX record locking dictates that any close releases ALL @@ -2142,13 +2186,9 @@ closef(struct file *fp, struct thread *td) * NULL thread pointer when there really is no owning * context that might have locks, or the locks will be * leaked. - * - * If this is a capability, we do lock processing under the underlying - * node, not the capability itself. */ - (void)cap_funwrap(fp, 0, &fp_object); - if (fp_object->f_type == DTYPE_VNODE && td != NULL) { - vp = fp_object->f_vnode; + if (fp->f_type == DTYPE_VNODE && td != NULL) { + vp = fp->f_vnode; if ((td->td_proc->p_leader->p_flag & P_ADVLOCK) != 0) { lf.l_whence = SEEK_SET; lf.l_start = 0; @@ -2177,7 +2217,7 @@ closef(struct file *fp, struct thread *td) lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; - vp = fp_object->f_vnode; + vp = fp->f_vnode; (void) VOP_ADVLOCK(vp, (caddr_t)fdtol->fdl_leader, F_UNLCK, &lf, F_POSIX); @@ -2211,14 +2251,19 @@ finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) atomic_store_rel_ptr((volatile uintptr_t *)&fp->f_ops, (uintptr_t)ops); } -struct file * -fget_unlocked(struct filedesc *fdp, int fd) +int +fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, + int needfcntl, struct file **fpp, cap_rights_t *haverightsp) { struct file *fp; u_int count; +#ifdef CAPABILITIES + cap_rights_t haverights; + int error; +#endif if (fd < 0 || fd >= fdp->fd_nfiles) - return (NULL); + return (EBADF); /* * Fetch the descriptor locklessly. We avoid fdrop() races by * never raising a refcount above 0. To accomplish this we have @@ -2228,9 +2273,20 @@ fget_unlocked(struct filedesc *fdp, int fd) * due to preemption. */ for (;;) { - fp = fdp->fd_ofiles[fd]; + fp = fdp->fd_ofiles[fd].fde_file; if (fp == NULL) - break; + return (EBADF); +#ifdef CAPABILITIES + haverights = cap_rights(fdp, fd); + error = cap_check(haverights, needrights); + if (error != 0) + return (error); + if ((needrights & CAP_FCNTL) != 0) { + error = cap_fcntl_check(fdp, fd, needfcntl); + if (error != 0) + return (error); + } +#endif count = fp->f_count; if (count == 0) continue; @@ -2240,12 +2296,19 @@ fget_unlocked(struct filedesc *fdp, int fd) */ if (atomic_cmpset_acq_int(&fp->f_count, count, count + 1) != 1) continue; - if (fp == fdp->fd_ofiles[fd]) + if (fp == fdp->fd_ofiles[fd].fde_file) break; fdrop(fp, curthread); } - - return (fp); + *fpp = fp; + if (haverightsp != NULL) { +#ifdef CAPABILITIES + *haverightsp = haverights; +#else + *haverightsp = CAP_ALL; +#endif + } + return (0); } /* @@ -2255,33 +2318,29 @@ fget_unlocked(struct filedesc *fdp, int fd) * If the descriptor doesn't exist or doesn't match 'flags', EBADF is * returned. * - * If the FGET_GETCAP flag is set, the capability itself will be returned. - * Calling _fget() with FGET_GETCAP on a non-capability will return EINVAL. - * Otherwise, if the file is a capability, its rights will be checked against - * the capability rights mask, and if successful, the object will be unwrapped. + * File's rights will be checked against the capability rights mask. * * If an error occured the non-zero error is returned and *fpp is set to * NULL. Otherwise *fpp is held and set and zero is returned. Caller is * responsible for fdrop(). */ -#define FGET_GETCAP 0x00000001 static __inline int _fget(struct thread *td, int fd, struct file **fpp, int flags, - cap_rights_t needrights, cap_rights_t *haverightsp, u_char *maxprotp, - int fget_flags) + cap_rights_t needrights, u_char *maxprotp) { struct filedesc *fdp; struct file *fp; -#ifdef CAPABILITIES - struct file *fp_fromcap; -#endif + cap_rights_t haverights; int error; *fpp = NULL; if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) return (EBADF); - if ((fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); + if (maxprotp != NULL) + needrights |= CAP_MMAP; + error = fget_unlocked(fdp, fd, needrights, 0, &fp, &haverights); + if (error != 0) + return (error); if (fp->f_ops == &badfileops) { fdrop(fp, td); return (EBADF); @@ -2289,50 +2348,11 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, #ifdef CAPABILITIES /* - * If this is a capability, what rights does it have? + * If requested, convert capability rights to access flags. */ - if (haverightsp != NULL) { - if (fp->f_type == DTYPE_CAPABILITY) - *haverightsp = cap_rights(fp); - else - *haverightsp = CAP_MASK_VALID; - } - - /* - * If a capability has been requested, return the capability directly. - * Otherwise, check capability rights, extract the underlying object, - * and check its access flags. - */ - if (fget_flags & FGET_GETCAP) { - if (fp->f_type != DTYPE_CAPABILITY) { - fdrop(fp, td); - return (EINVAL); - } - } else { - if (maxprotp == NULL) - error = cap_funwrap(fp, needrights, &fp_fromcap); - else - error = cap_funwrap_mmap(fp, needrights, maxprotp, - &fp_fromcap); - if (error != 0) { - fdrop(fp, td); - return (error); - } - - /* - * If we've unwrapped a file, drop the original capability - * and hold the new descriptor. fp after this point refers to - * the actual (unwrapped) object, not the capability. - */ - if (fp != fp_fromcap) { - fhold(fp_fromcap); - fdrop(fp, td); - fp = fp_fromcap; - } - } + if (maxprotp != NULL) + *maxprotp = cap_rights_to_vmprot(haverights); #else /* !CAPABILITIES */ - KASSERT(fp->f_type != DTYPE_CAPABILITY, - ("%s: saw capability", __func__)); if (maxprotp != NULL) *maxprotp = VM_PROT_ALL; #endif /* CAPABILITIES */ @@ -2371,7 +2391,7 @@ int fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) { - return(_fget(td, fd, fpp, 0, rights, NULL, NULL, 0)); + return(_fget(td, fd, fpp, 0, rights, NULL)); } int @@ -2379,37 +2399,24 @@ fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp, struct file **fpp) { - return (_fget(td, fd, fpp, 0, rights, NULL, maxprotp, 0)); + return (_fget(td, fd, fpp, 0, rights, maxprotp)); } int fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) { - return(_fget(td, fd, fpp, FREAD, rights, NULL, NULL, 0)); + return(_fget(td, fd, fpp, FREAD, rights, NULL)); } int fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) { - return (_fget(td, fd, fpp, FWRITE, rights, NULL, NULL, 0)); + return (_fget(td, fd, fpp, FWRITE, rights, NULL)); } /* - * Unlike the other fget() calls, which accept and check capability rights - * but never return capabilities, fgetcap() returns the capability but doesn't - * check capability rights. - */ -int -fgetcap(struct thread *td, int fd, struct file **fpp) -{ - - return (_fget(td, fd, fpp, 0, 0, NULL, NULL, FGET_GETCAP)); -} - - -/* * Like fget() but loads the underlying vnode, or returns an error if the * descriptor does not represent a vnode. Note that pipes use vnodes but * never have VM objects. The returned vnode will be vref()'d. @@ -2418,14 +2425,14 @@ fgetcap(struct thread *td, int fd, struct file **fpp) */ static __inline int _fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights, - cap_rights_t *haverightsp, struct vnode **vpp) + struct vnode **vpp) { struct file *fp; int error; *vpp = NULL; - if ((error = _fget(td, fd, &fp, flags, needrights, haverightsp, - NULL, 0)) != 0) + error = _fget(td, fd, &fp, flags, needrights, NULL); + if (error) return (error); if (fp->f_vnode == NULL) { error = EINVAL; @@ -2442,28 +2449,54 @@ int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, 0, rights, NULL, vpp)); + return (_fgetvp(td, fd, 0, rights, vpp)); } int -fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have, - struct vnode **vpp) +fgetvp_rights(struct thread *td, int fd, cap_rights_t need, + struct filecaps *havecaps, struct vnode **vpp) { - return (_fgetvp(td, fd, 0, need, have, vpp)); + struct filedesc *fdp; + struct file *fp; +#ifdef CAPABILITIES + int error; +#endif + + if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) + return (EBADF); + + fp = fget_locked(fdp, fd); + if (fp == NULL || fp->f_ops == &badfileops) + return (EBADF); + +#ifdef CAPABILITIES + error = cap_check(cap_rights(fdp, fd), need); + if (error != 0) + return (error); +#endif + + if (fp->f_vnode == NULL) + return (EINVAL); + + *vpp = fp->f_vnode; + vref(*vpp); + filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecaps); + + return (0); } int fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, FREAD, rights, NULL, vpp)); + return (_fgetvp(td, fd, FREAD, rights, vpp)); } int fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, FEXEC, rights, NULL, vpp)); + return (_fgetvp(td, fd, FEXEC, rights, vpp)); } #ifdef notyet @@ -2472,7 +2505,7 @@ fgetvp_write(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, FWRITE, rights, NULL, vpp)); + return (_fgetvp(td, fd, FWRITE, rights, vpp)); } #endif @@ -2497,7 +2530,7 @@ fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp, *spp = NULL; if (fflagp != NULL) *fflagp = 0; - if ((error = _fget(td, fd, &fp, 0, rights, NULL, NULL, 0)) != 0) + if ((error = _fget(td, fd, &fp, 0, rights, NULL)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { error = ENOTSOCK; @@ -2533,9 +2566,6 @@ fputsock(struct socket *so) /* * Handle the last reference to a file being closed. - * - * No special capability handling here, as the capability's fo_close will run - * instead of the object here, and perform any necessary drop on the object. */ int _fdrop(struct file *fp, struct thread *td) @@ -2612,7 +2642,8 @@ done2: * Duplicate the specified descriptor to a free descriptor. */ int -dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, int openerror, int *indxp) +dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, + int openerror, int *indxp) { struct file *fp; int error, indx; @@ -2656,18 +2687,17 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, int opener FILEDESC_XUNLOCK(fdp); return (EACCES); } - fdp->fd_ofiles[indx] = fp; - fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; fhold(fp); + fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; + filecaps_copy(&fdp->fd_ofiles[dfd].fde_caps, + &fdp->fd_ofiles[indx].fde_caps); break; case ENXIO: /* * Steal away the file pointer from dfd and stuff it into indx. */ - fdp->fd_ofiles[indx] = fp; - fdp->fd_ofiles[dfd] = NULL; - fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; - fdp->fd_ofileflags[dfd] = 0; + fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; + bzero(&fdp->fd_ofiles[dfd], sizeof(fdp->fd_ofiles[dfd])); fdunused(fdp, dfd); break; } @@ -2823,7 +2853,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS) continue; FILEDESC_SLOCK(fdp); for (n = 0; fdp->fd_refcnt > 0 && n < fdp->fd_nfiles; ++n) { - if ((fp = fdp->fd_ofiles[n]) == NULL) + if ((fp = fdp->fd_ofiles[n].fde_file) == NULL) continue; xf.xf_fd = n; xf.xf_file = fp; @@ -2935,7 +2965,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif, fdp, req); for (i = 0; i < fdp->fd_nfiles; i++) { - if ((fp = fdp->fd_ofiles[i]) == NULL) + if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) continue; bzero(kif, sizeof(*kif)); kif->kf_structsize = sizeof(*kif); @@ -2945,21 +2975,6 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) shmfd = NULL; kif->kf_fd = i; -#ifdef CAPABILITIES - /* - * When reporting a capability, most fields will be from the - * underlying object, but do mark as a capability. With - * ofiledesc, we don't have a field to export the cap_rights_t, - * but we do with the new filedesc. - */ - if (fp->f_type == DTYPE_CAPABILITY) { - kif->kf_flags |= KF_FLAG_CAPABILITY; - (void)cap_funwrap(fp, 0, &fp); - } -#else - KASSERT(fp->f_type != DTYPE_CAPABILITY, - ("sysctl_kern_proc_ofiledesc: saw capability")); -#endif switch (fp->f_type) { case DTYPE_VNODE: kif->kf_type = KF_TYPE_VNODE; @@ -3128,8 +3143,8 @@ CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE); static int export_fd_for_sysctl(void *data, int type, int fd, int fflags, int refcnt, - int64_t offset, int fd_is_cap, cap_rights_t fd_cap_rights, - struct kinfo_file *kif, struct sysctl_req *req) + int64_t offset, cap_rights_t fd_cap_rights, struct kinfo_file *kif, + struct sysctl_req *req) { struct { int fflag; @@ -3191,10 +3206,7 @@ export_fd_for_sysctl(void *data, int type, int fd, int fflags, int refcnt, for (i = 0; i < NFFLAGS; i++) if (fflags & fflags_table[i].fflag) kif->kf_flags |= fflags_table[i].kf_fflag; - if (fd_is_cap) - kif->kf_flags |= KF_FLAG_CAPABILITY; - if (fd_is_cap) - kif->kf_cap_rights = fd_cap_rights; + kif->kf_cap_rights = fd_cap_rights; kif->kf_fd = fd; kif->kf_type = type; kif->kf_ref_count = refcnt; @@ -3222,7 +3234,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) int64_t offset; void *data; int error, i, *name; - int fd_is_cap, type, refcnt, fflags; + int type, refcnt, fflags; cap_rights_t fd_cap_rights; name = (int *)arg1; @@ -3252,13 +3264,13 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); if (tracevp != NULL) export_fd_for_sysctl(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE, - FREAD | FWRITE, -1, -1, 0, 0, kif, req); + FREAD | FWRITE, -1, -1, 0, kif, req); if (textvp != NULL) export_fd_for_sysctl(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT, - FREAD, -1, -1, 0, 0, kif, req); + FREAD, -1, -1, 0, kif, req); if (cttyvp != NULL) export_fd_for_sysctl(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY, - FREAD | FWRITE, -1, -1, 0, 0, kif, req); + FREAD | FWRITE, -1, -1, 0, kif, req); if (fdp == NULL) goto fail; FILEDESC_SLOCK(fdp); @@ -3268,7 +3280,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) data = fdp->fd_cdir; FILEDESC_SUNLOCK(fdp); export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD, - FREAD, -1, -1, 0, 0, kif, req); + FREAD, -1, -1, 0, kif, req); FILEDESC_SLOCK(fdp); } /* root directory */ @@ -3277,7 +3289,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) data = fdp->fd_rdir; FILEDESC_SUNLOCK(fdp); export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT, - FREAD, -1, -1, 0, 0, kif, req); + FREAD, -1, -1, 0, kif, req); FILEDESC_SLOCK(fdp); } /* jail directory */ @@ -3286,30 +3298,17 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) data = fdp->fd_jdir; FILEDESC_SUNLOCK(fdp); export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL, - FREAD, -1, -1, 0, 0, kif, req); + FREAD, -1, -1, 0, kif, req); FILEDESC_SLOCK(fdp); } for (i = 0; i < fdp->fd_nfiles; i++) { - if ((fp = fdp->fd_ofiles[i]) == NULL) + if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) continue; data = NULL; - fd_is_cap = 0; - fd_cap_rights = 0; - #ifdef CAPABILITIES - /* - * When reporting a capability, most fields will be from the - * underlying object, but do mark as a capability and export - * the capability rights mask. - */ - if (fp->f_type == DTYPE_CAPABILITY) { - fd_is_cap = 1; - fd_cap_rights = cap_rights(fp); - (void)cap_funwrap(fp, 0, &fp); - } + fd_cap_rights = cap_rights(fdp, i); #else /* !CAPABILITIES */ - KASSERT(fp->f_type != DTYPE_CAPABILITY, - ("sysctl_kern_proc_filedesc: saw capability")); + fd_cap_rights = 0; #endif switch (fp->f_type) { case DTYPE_VNODE: @@ -3385,7 +3384,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO) FILEDESC_SUNLOCK(fdp); error = export_fd_for_sysctl(data, type, i, fflags, refcnt, - offset, fd_is_cap, fd_cap_rights, kif, req); + offset, fd_cap_rights, kif, req); if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO) FILEDESC_SLOCK(fdp); if (error) { @@ -3644,7 +3643,7 @@ file_to_first_proc(struct file *fp) if (fdp == NULL) continue; for (n = 0; n < fdp->fd_nfiles; n++) { - if (fp == fdp->fd_ofiles[n]) + if (fp == fdp->fd_ofiles[n].fde_file) return (p); } } @@ -3694,7 +3693,7 @@ DB_SHOW_COMMAND(files, db_show_files) if ((fdp = p->p_fd) == NULL) continue; for (n = 0; n < fdp->fd_nfiles; ++n) { - if ((fp = fdp->fd_ofiles[n]) == NULL) + if ((fp = fdp->fd_ofiles[n].fde_file) == NULL) continue; db_print_file(fp, header); header = 0; diff --git a/sys/kern/kern_et.c b/sys/kern/kern_et.c index 3156c81..472db79 100644 --- a/sys/kern/kern_et.c +++ b/sys/kern/kern_et.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> + * Copyright (c) 2010-2013 Alexander Motin <mav@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,6 +62,7 @@ et_register(struct eventtimer *et) et->et_quality); } } + KASSERT(et->et_start, ("et_register: timer has no start function")); et->et_sysctl = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name, CTLFLAG_RW, 0, "event timer description"); @@ -159,43 +160,29 @@ et_init(struct eventtimer *et, et_event_cb_t *event, * period - period of subsequent periodic ticks. */ int -et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { if (!et->et_active) return (ENXIO); - if (first == NULL && period == NULL) - return (EINVAL); - if ((et->et_flags & ET_FLAGS_PERIODIC) == 0 && - period != NULL) - return (ENODEV); - if ((et->et_flags & ET_FLAGS_ONESHOT) == 0 && - period == NULL) - return (ENODEV); - if (first != NULL) { - if (first->sec < et->et_min_period.sec || - (first->sec == et->et_min_period.sec && - first->frac < et->et_min_period.frac)) - first = &et->et_min_period; - if (first->sec > et->et_max_period.sec || - (first->sec == et->et_max_period.sec && - first->frac > et->et_max_period.frac)) - first = &et->et_max_period; + KASSERT(period >= 0, ("et_start: negative period")); + KASSERT((et->et_flags & ET_FLAGS_PERIODIC) || period == 0, + ("et_start: period specified for oneshot-only timer")); + KASSERT((et->et_flags & ET_FLAGS_ONESHOT) && period == 0, + ("et_start: period not specified for periodic-only timer")); + if (period != 0) { + if (period < et->et_min_period) + period = et->et_min_period; + else if (period > et->et_max_period) + period = et->et_max_period; } - if (period != NULL) { - if (period->sec < et->et_min_period.sec || - (period->sec == et->et_min_period.sec && - period->frac < et->et_min_period.frac)) - period = &et->et_min_period; - if (period->sec > et->et_max_period.sec || - (period->sec == et->et_max_period.sec && - period->frac > et->et_max_period.frac)) - period = &et->et_max_period; + if (period == 0 || first != 0) { + if (first < et->et_min_period) + first = et->et_min_period; + else if (first > et->et_max_period) + first = et->et_max_period; } - if (et->et_start) - return (et->et_start(et, first, period)); - return (0); + return (et->et_start(et, first, period)); } /* Stop event timer hardware. */ diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 6f9ff4f..3890157 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -439,9 +439,6 @@ interpret: } else { AUDIT_ARG_FD(args->fd); /* - * Some might argue that CAP_READ and/or CAP_MMAP should also - * be required here; such arguments will be entertained. - * * Descriptors opened only with O_EXEC or O_RDONLY are allowed. */ error = fgetvp_exec(td, args->fd, CAP_FEXECVE, &binvp); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 82f0344..5bd2daa 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -297,7 +297,7 @@ exit1(struct thread *td, int rv) * Close open files and release open-file table. * This may block! */ - fdfree(td); + fdescfree(td); /* * If this thread tickled GEOM, we need to wait for the giggling to diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 287d202..b5a4934 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -342,7 +342,7 @@ fork_norfproc(struct thread *td, int flags) if (flags & RFCFDG) { struct filedesc *fdtmp; fdtmp = fdinit(td->td_proc->p_fd); - fdfree(td); + fdescfree(td); p1->p_fd = fdtmp; } diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 33296d3..68bf453 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -444,9 +444,9 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse) SYSCTL_SLEEP(&oidp->oid_running, "oidrm", 0); } if (oidp->oid_descr) - free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID); - free((void *)(uintptr_t)(const void *)oidp->oid_name, - M_SYSCTLOID); + free(__DECONST(char *, oidp->oid_descr), + M_SYSCTLOID); + free(__DECONST(char *, oidp->oid_name), M_SYSCTLOID); free(oidp, M_SYSCTLOID); } } @@ -462,8 +462,6 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr) { struct sysctl_oid *oidp; - ssize_t len; - char *newname; /* You have to hook up somewhere.. */ if (parent == NULL) @@ -490,11 +488,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, SLIST_NEXT(oidp, oid_link) = NULL; oidp->oid_number = number; oidp->oid_refcnt = 1; - len = strlen(name); - newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); - bcopy(name, newname, len + 1); - newname[len] = '\0'; - oidp->oid_name = newname; + oidp->oid_name = strdup(name, M_SYSCTLOID); oidp->oid_handler = handler; oidp->oid_kind = CTLFLAG_DYN | kind; if ((kind & CTLTYPE) == CTLTYPE_NODE) { @@ -508,12 +502,8 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, oidp->oid_arg2 = arg2; } oidp->oid_fmt = fmt; - if (descr) { - int len = strlen(descr) + 1; - oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK); - if (oidp->oid_descr) - strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr); - } + if (descr) + oidp->oid_descr = strdup(descr, M_SYSCTLOID); /* Update the context, if used */ if (clist != NULL) sysctl_ctx_entry_add(clist, oidp); @@ -529,16 +519,12 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, void sysctl_rename_oid(struct sysctl_oid *oidp, const char *name) { - ssize_t len; char *newname; - void *oldname; + char *oldname; - len = strlen(name); - newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); - bcopy(name, newname, len + 1); - newname[len] = '\0'; + newname = strdup(name, M_SYSCTLOID); SYSCTL_XLOCK(); - oldname = (void *)(uintptr_t)(const void *)oidp->oid_name; + oldname = __DECONST(char *, oidp->oid_name); oidp->oid_name = newname; SYSCTL_XUNLOCK(); free(oldname, M_SYSCTLOID); @@ -823,39 +809,26 @@ static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_CAPRD, static int name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp) { - int i; struct sysctl_oid *oidp; struct sysctl_oid_list *lsp = &sysctl__children; char *p; SYSCTL_ASSERT_XLOCKED(); - if (!*name) - return (ENOENT); - - p = name + strlen(name) - 1 ; - if (*p == '.') - *p = '\0'; - - *len = 0; + for (*len = 0; *len < CTL_MAXNAME;) { + p = strsep(&name, "."); - for (p = name; *p && *p != '.'; p++) - ; - i = *p; - if (i == '.') - *p = '\0'; - - oidp = SLIST_FIRST(lsp); - - while (oidp && *len < CTL_MAXNAME) { - if (strcmp(name, oidp->oid_name)) { - oidp = SLIST_NEXT(oidp, oid_link); - continue; + oidp = SLIST_FIRST(lsp); + for (;; oidp = SLIST_NEXT(oidp, oid_link)) { + if (oidp == NULL) + return (ENOENT); + if (strcmp(p, oidp->oid_name) == 0) + break; } *oid++ = oidp->oid_number; (*len)++; - if (!i) { + if (name == NULL || *name == '\0') { if (oidpp) *oidpp = oidp; return (0); @@ -868,13 +841,6 @@ name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp) break; lsp = SYSCTL_CHILDREN(oidp); - oidp = SLIST_FIRST(lsp); - name = p+1; - for (p = name; *p && *p != '.'; p++) - ; - i = *p; - if (i == '.') - *p = '\0'; } return (ENOENT); } diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 80933fa..9cdc39b 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -100,7 +100,7 @@ struct cc_mig_ent { int ce_migration_ticks; #endif }; - + /* * There is one struct callout_cpu per cpu, holding all relevant * state for the callout processing thread on the individual CPU. @@ -613,7 +613,7 @@ skip: } /* - * The callout mechanism is based on the work of Adam M. Costello and + * The callout mechanism is based on the work of Adam M. Costello and * George Varghese, published in a technical report entitled "Redesigning * the BSD Callout and Timer Facilities" and modified slightly for inclusion * in FreeBSD by Justin T. Gibbs. The original work on the data structures diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index b6bd8fc..f187544 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -296,8 +296,8 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags, MPASS((queue >= 0) && (queue < NR_SLEEPQS)); /* If this thread is not allowed to sleep, die a horrible death. */ - KASSERT(!(td->td_pflags & TDP_NOSLEEPING), - ("%s: td %p to sleep on wchan %p with TDP_NOSLEEPING on", + KASSERT(td->td_no_sleeping == 0, + ("%s: td %p to sleep on wchan %p with sleeping prohibited", __func__, td, wchan)); /* Look up the sleep queue associated with the wait channel 'wchan'. */ diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index bd06f20..1f24e88 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -158,7 +158,7 @@ userret(struct thread *td, struct trapframe *frame) ("userret: Returning with %d locks held", td->td_locks)); KASSERT((td->td_pflags & TDP_NOFAULTING) == 0, ("userret: Returning with pagefaults disabled")); - KASSERT((td->td_pflags & TDP_NOSLEEPING) == 0, + KASSERT(td->td_no_sleeping == 0, ("userret: Returning with sleep disabled")); KASSERT(td->td_pinned == 0 || (td->td_pflags & TDP_CALLCHAIN) != 0, ("userret: Returning with with pinned thread")); diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 6fb4fee..ba168e9 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -1,11 +1,15 @@ /*- * Copyright (c) 2008-2011 Robert N. M. Watson * Copyright (c) 2010-2011 Jonathan Anderson + * Copyright (c) 2012 FreeBSD Foundation * All rights reserved. * * This software was developed at the University of Cambridge Computer * Laboratory with support from a grant from Google, Inc. * + * Portions of this software were developed by Pawel Jakub Dawidek under + * sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -62,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include <sys/file.h> #include <sys/filedesc.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/proc.h> @@ -139,90 +144,48 @@ sys_cap_getmode(struct thread *td, struct cap_getmode_args *uap) FEATURE(security_capabilities, "Capsicum Capabilities"); -/* - * struct capability describes a capability, and is hung off of its struct - * file f_data field. cap_file and cap_rightss are static once hooked up, as - * neither the object it references nor the rights it encapsulates are - * permitted to change. - */ -struct capability { - struct file *cap_object; /* Underlying object's file. */ - struct file *cap_file; /* Back-pointer to cap's file. */ - cap_rights_t cap_rights; /* Mask of rights on object. */ -}; +static inline int +_cap_check(cap_rights_t have, cap_rights_t need, enum ktr_cap_fail_type type) +{ + + + if ((need & ~have) != 0) { +#ifdef KTRACE + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(type, need, have); +#endif + return (ENOTCAPABLE); + } + return (0); +} /* - * Capabilities have a fileops vector, but in practice none should ever be - * called except for fo_close, as the capability will normally not be - * returned during a file descriptor lookup in the system call code. + * Test whether a capability grants the requested rights. */ -static fo_rdwr_t capability_read; -static fo_rdwr_t capability_write; -static fo_truncate_t capability_truncate; -static fo_ioctl_t capability_ioctl; -static fo_poll_t capability_poll; -static fo_kqfilter_t capability_kqfilter; -static fo_stat_t capability_stat; -static fo_close_t capability_close; -static fo_chmod_t capability_chmod; -static fo_chown_t capability_chown; - -static struct fileops capability_ops = { - .fo_read = capability_read, - .fo_write = capability_write, - .fo_truncate = capability_truncate, - .fo_ioctl = capability_ioctl, - .fo_poll = capability_poll, - .fo_kqfilter = capability_kqfilter, - .fo_stat = capability_stat, - .fo_close = capability_close, - .fo_chmod = capability_chmod, - .fo_chown = capability_chown, - .fo_flags = DFLAG_PASSABLE, -}; - -static struct fileops capability_ops_unpassable = { - .fo_read = capability_read, - .fo_write = capability_write, - .fo_truncate = capability_truncate, - .fo_ioctl = capability_ioctl, - .fo_poll = capability_poll, - .fo_kqfilter = capability_kqfilter, - .fo_stat = capability_stat, - .fo_close = capability_close, - .fo_chmod = capability_chmod, - .fo_chown = capability_chown, - .fo_flags = 0, -}; - -static uma_zone_t capability_zone; - -static void -capability_init(void *dummy __unused) +int +cap_check(cap_rights_t have, cap_rights_t need) { - capability_zone = uma_zcreate("capability", sizeof(struct capability), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - if (capability_zone == NULL) - panic("capability_init: capability_zone not initialized"); + return (_cap_check(have, need, CAPFAIL_NOTCAPABLE)); } -SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, capability_init, NULL); /* - * Test whether a capability grants the requested rights. + * Convert capability rights into VM access flags. */ -static int -cap_check(struct capability *c, cap_rights_t rights) +u_char +cap_rights_to_vmprot(cap_rights_t have) { + u_char maxprot; - if ((c->cap_rights | rights) != c->cap_rights) { -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(CAPFAIL_NOTCAPABLE, rights, c->cap_rights); -#endif - return (ENOTCAPABLE); - } - return (0); + maxprot = VM_PROT_NONE; + if (have & CAP_MMAP_R) + maxprot |= VM_PROT_READ; + if (have & CAP_MMAP_W) + maxprot |= VM_PROT_WRITE; + if (have & CAP_MMAP_X) + maxprot |= VM_PROT_EXECUTE; + + return (maxprot); } /* @@ -231,43 +194,49 @@ cap_check(struct capability *c, cap_rights_t rights) * this one file. */ cap_rights_t -cap_rights(struct file *fp_cap) +cap_rights(struct filedesc *fdp, int fd) { - struct capability *c; - - KASSERT(fp_cap->f_type == DTYPE_CAPABILITY, - ("cap_rights: !capability")); - c = fp_cap->f_data; - return (c->cap_rights); + return (fdp->fd_ofiles[fd].fde_rights); } /* - * System call to create a new capability reference to either an existing - * file object or an an existing capability. + * System call to limit rights of the given capability. */ int -sys_cap_new(struct thread *td, struct cap_new_args *uap) +sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) { - int error, capfd; - int fd = uap->fd; - struct file *fp; - cap_rights_t rights = uap->rights; + struct filedesc *fdp; + cap_rights_t rights; + int error, fd; + + fd = uap->fd; + rights = uap->rights; AUDIT_ARG_FD(fd); AUDIT_ARG_RIGHTS(rights); - error = fget(td, fd, rights, &fp); - if (error) - return (error); - AUDIT_ARG_FILE(td->td_proc, fp); - error = kern_capwrap(td, fp, rights, &capfd); - /* - * Release our reference to the file (kern_capwrap has held a reference - * for the filedesc array). - */ - fdrop(fp, td); - if (error == 0) - td->td_retval[0] = capfd; + + if ((rights & ~CAP_ALL) != 0) + return (EINVAL); + + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_XUNLOCK(fdp); + return (EBADF); + } + error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); + if (error == 0) { + fdp->fd_ofiles[fd].fde_rights = rights; + if ((rights & CAP_IOCTL) == 0) { + free(fdp->fd_ofiles[fd].fde_ioctls, M_TEMP); + fdp->fd_ofiles[fd].fde_ioctls = NULL; + fdp->fd_ofiles[fd].fde_nioctls = 0; + } + if ((rights & CAP_FCNTL) == 0) + fdp->fd_ofiles[fd].fde_fcntls = 0; + } + FILEDESC_XUNLOCK(fdp); return (error); } @@ -275,247 +244,321 @@ sys_cap_new(struct thread *td, struct cap_new_args *uap) * System call to query the rights mask associated with a capability. */ int -sys_cap_getrights(struct thread *td, struct cap_getrights_args *uap) +sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap) { - struct capability *cp; - struct file *fp; - int error; + struct filedesc *fdp; + cap_rights_t rights; + int fd; - AUDIT_ARG_FD(uap->fd); - error = fgetcap(td, uap->fd, &fp); - if (error) - return (error); - cp = fp->f_data; - error = copyout(&cp->cap_rights, uap->rightsp, sizeof(*uap->rightsp)); - fdrop(fp, td); - return (error); + fd = uap->fd; + + AUDIT_ARG_FD(fd); + + fdp = td->td_proc->p_fd; + FILEDESC_SLOCK(fdp); + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_SUNLOCK(fdp); + return (EBADF); + } + rights = cap_rights(fdp, fd); + FILEDESC_SUNLOCK(fdp); + return (copyout(&rights, uap->rightsp, sizeof(*uap->rightsp))); } /* - * Create a capability to wrap around an existing file. + * Test whether a capability grants the given ioctl command. + * If descriptor doesn't have CAP_IOCTL, then ioctls list is empty and + * ENOTCAPABLE will be returned. */ int -kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, - int *capfdp) +cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd) { - struct capability *cp, *cp_old; - struct file *fp_object, *fcapp; - int error; - - if ((rights | CAP_MASK_VALID) != CAP_MASK_VALID) - return (EINVAL); + u_long *cmds; + ssize_t ncmds; + long i; - /* - * If a new capability is being derived from an existing capability, - * then the new capability rights must be a subset of the existing - * rights. - */ - if (fp->f_type == DTYPE_CAPABILITY) { - cp_old = fp->f_data; - if ((cp_old->cap_rights | rights) != cp_old->cap_rights) { -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(CAPFAIL_INCREASE, - rights, cp_old->cap_rights); -#endif - return (ENOTCAPABLE); - } - } + FILEDESC_LOCK_ASSERT(fdp); + KASSERT(fd >= 0 && fd < fdp->fd_nfiles, + ("%s: invalid fd=%d", __func__, fd)); - /* - * Allocate a new file descriptor to hang the capability off of. - */ - error = falloc(td, &fcapp, capfdp, fp->f_flag); - if (error) - return (error); + ncmds = fdp->fd_ofiles[fd].fde_nioctls; + if (ncmds == -1) + return (0); - /* - * Rather than nesting capabilities, directly reference the object an - * existing capability references. There's nothing else interesting - * to preserve for future use, as we've incorporated the previous - * rights mask into the new one. This prevents us from having to - * deal with capability chains. - */ - if (fp->f_type == DTYPE_CAPABILITY) - fp_object = ((struct capability *)fp->f_data)->cap_object; - else - fp_object = fp; - fhold(fp_object); - cp = uma_zalloc(capability_zone, M_WAITOK | M_ZERO); - cp->cap_rights = rights; - cp->cap_object = fp_object; - cp->cap_file = fcapp; - if (fp->f_flag & DFLAG_PASSABLE) - finit(fcapp, fp->f_flag, DTYPE_CAPABILITY, cp, - &capability_ops); - else - finit(fcapp, fp->f_flag, DTYPE_CAPABILITY, cp, - &capability_ops_unpassable); + cmds = fdp->fd_ofiles[fd].fde_ioctls; + for (i = 0; i < ncmds; i++) { + if (cmds[i] == cmd) + return (0); + } - /* - * Release our private reference (the proc filedesc still has one). - */ - fdrop(fcapp, td); - return (0); + return (ENOTCAPABLE); } /* - * Given a file descriptor, test it against a capability rights mask and then - * return the file descriptor on which to actually perform the requested - * operation. As long as the reference to fp_cap remains valid, the returned - * pointer in *fp will remain valid, so no extra reference management is - * required, and the caller should fdrop() fp_cap as normal when done with - * both. + * Check if the current ioctls list can be replaced by the new one. */ -int -cap_funwrap(struct file *fp_cap, cap_rights_t rights, struct file **fpp) +static int +cap_ioctl_limit_check(struct filedesc *fdp, int fd, const u_long *cmds, + size_t ncmds) { - struct capability *c; - int error; + u_long *ocmds; + ssize_t oncmds; + u_long i; + long j; - if (fp_cap->f_type != DTYPE_CAPABILITY) { - *fpp = fp_cap; + oncmds = fdp->fd_ofiles[fd].fde_nioctls; + if (oncmds == -1) return (0); + if (oncmds < (ssize_t)ncmds) + return (ENOTCAPABLE); + + ocmds = fdp->fd_ofiles[fd].fde_ioctls; + for (i = 0; i < ncmds; i++) { + for (j = 0; j < oncmds; j++) { + if (cmds[i] == ocmds[j]) + break; + } + if (j == oncmds) + return (ENOTCAPABLE); } - c = fp_cap->f_data; - error = cap_check(c, rights); - if (error) - return (error); - *fpp = c->cap_object; + return (0); } -/* - * Slightly different routine for memory mapping file descriptors: unwrap the - * capability and check CAP_MMAP, but also return a bitmask representing the - * maximum mapping rights the capability allows on the object. - */ int -cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp, - struct file **fpp) +sys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap) { - struct capability *c; - u_char maxprot; - int error; + struct filedesc *fdp; + u_long *cmds, *ocmds; + size_t ncmds; + int error, fd; - if (fp_cap->f_type != DTYPE_CAPABILITY) { - *fpp = fp_cap; - *maxprotp = VM_PROT_ALL; - return (0); + fd = uap->fd; + ncmds = uap->ncmds; + + AUDIT_ARG_FD(fd); + + if (ncmds > 256) /* XXX: Is 256 sane? */ + return (EINVAL); + + if (ncmds == 0) { + cmds = NULL; + } else { + cmds = malloc(sizeof(cmds[0]) * ncmds, M_TEMP, M_WAITOK); + error = copyin(uap->cmds, cmds, sizeof(cmds[0]) * ncmds); + if (error != 0) { + free(cmds, M_TEMP); + return (error); + } } - c = fp_cap->f_data; - error = cap_check(c, rights | CAP_MMAP); - if (error) - return (error); - *fpp = c->cap_object; - maxprot = 0; - if (c->cap_rights & CAP_READ) - maxprot |= VM_PROT_READ; - if (c->cap_rights & CAP_WRITE) - maxprot |= VM_PROT_WRITE; - if (c->cap_rights & CAP_MAPEXEC) - maxprot |= VM_PROT_EXECUTE; - *maxprotp = maxprot; - return (0); + + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + + if (fget_locked(fdp, fd) == NULL) { + error = EBADF; + goto out; + } + + error = cap_ioctl_limit_check(fdp, fd, cmds, ncmds); + if (error != 0) + goto out; + + ocmds = fdp->fd_ofiles[fd].fde_ioctls; + fdp->fd_ofiles[fd].fde_ioctls = cmds; + fdp->fd_ofiles[fd].fde_nioctls = ncmds; + + cmds = ocmds; + error = 0; +out: + FILEDESC_XUNLOCK(fdp); + free(cmds, M_TEMP); + return (error); } -/* - * When a capability is closed, simply drop the reference on the underlying - * object and free the capability. fdrop() will handle the case where the - * underlying object also needs to close, and the caller will have already - * performed any object-specific lock or mqueue handling. - */ -static int -capability_close(struct file *fp, struct thread *td) +int +sys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) { - struct capability *c; - struct file *fp_object; - - KASSERT(fp->f_type == DTYPE_CAPABILITY, - ("capability_close: !capability")); - - c = fp->f_data; - fp->f_ops = &badfileops; - fp->f_data = NULL; - fp_object = c->cap_object; - uma_zfree(capability_zone, c); - return (fdrop(fp_object, td)); + struct filedesc *fdp; + struct filedescent *fdep; + u_long *cmds; + size_t maxcmds; + int error, fd; + + fd = uap->fd; + cmds = uap->cmds; + maxcmds = uap->maxcmds; + + AUDIT_ARG_FD(fd); + + fdp = td->td_proc->p_fd; + FILEDESC_SLOCK(fdp); + + if (fget_locked(fdp, fd) == NULL) { + error = EBADF; + goto out; + } + + /* + * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL) + * the only sane thing we can do is to not populate the given array and + * return CAP_IOCTLS_ALL. + */ + + fdep = &fdp->fd_ofiles[fd]; + if (cmds != NULL && fdep->fde_ioctls != NULL) { + error = copyout(fdep->fde_ioctls, cmds, + sizeof(cmds[0]) * MIN(fdep->fde_nioctls, maxcmds)); + if (error != 0) + goto out; + } + if (fdep->fde_nioctls == -1) + td->td_retval[0] = CAP_IOCTLS_ALL; + else + td->td_retval[0] = fdep->fde_nioctls; + + error = 0; +out: + FILEDESC_SUNLOCK(fdp); + return (error); } /* - * In general, file descriptor operations should never make it to the - * capability, only the underlying file descriptor operation vector, so panic - * if we do turn up here. + * Test whether a capability grants the given fcntl command. */ -static int -capability_read(struct file *fp, struct uio *uio, struct ucred *active_cred, - int flags, struct thread *td) +int +cap_fcntl_check(struct filedesc *fdp, int fd, int cmd) { + uint32_t fcntlcap; - panic("capability_read"); -} - -static int -capability_write(struct file *fp, struct uio *uio, struct ucred *active_cred, - int flags, struct thread *td) -{ + KASSERT(fd >= 0 && fd < fdp->fd_nfiles, + ("%s: invalid fd=%d", __func__, fd)); - panic("capability_write"); -} + fcntlcap = (1 << cmd); + KASSERT((CAP_FCNTL_ALL & fcntlcap) != 0, + ("Unsupported fcntl=%d.", cmd)); -static int -capability_truncate(struct file *fp, off_t length, struct ucred *active_cred, - struct thread *td) -{ + if ((fdp->fd_ofiles[fd].fde_fcntls & fcntlcap) != 0) + return (0); - panic("capability_truncate"); + return (ENOTCAPABLE); } -static int -capability_ioctl(struct file *fp, u_long com, void *data, - struct ucred *active_cred, struct thread *td) +int +sys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) { + struct filedesc *fdp; + uint32_t fcntlrights; + int fd; - panic("capability_ioctl"); -} + fd = uap->fd; + fcntlrights = uap->fcntlrights; -static int -capability_poll(struct file *fp, int events, struct ucred *active_cred, - struct thread *td) -{ + AUDIT_ARG_FD(fd); + AUDIT_ARG_FCNTL_RIGHTS(fcntlrights); - panic("capability_poll"); -} + if ((fcntlrights & ~CAP_FCNTL_ALL) != 0) + return (EINVAL); -static int -capability_kqfilter(struct file *fp, struct knote *kn) -{ + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); - panic("capability_kqfilter"); -} + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_XUNLOCK(fdp); + return (EBADF); + } -static int -capability_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, - struct thread *td) -{ + if ((fcntlrights & ~fdp->fd_ofiles[fd].fde_fcntls) != 0) { + FILEDESC_XUNLOCK(fdp); + return (ENOTCAPABLE); + } - panic("capability_stat"); + fdp->fd_ofiles[fd].fde_fcntls = fcntlrights; + FILEDESC_XUNLOCK(fdp); + + return (0); } int -capability_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, - struct thread *td) +sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) { + struct filedesc *fdp; + uint32_t rights; + int fd; + + fd = uap->fd; - panic("capability_chmod"); + AUDIT_ARG_FD(fd); + + fdp = td->td_proc->p_fd; + FILEDESC_SLOCK(fdp); + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_SUNLOCK(fdp); + return (EBADF); + } + rights = fdp->fd_ofiles[fd].fde_fcntls; + FILEDESC_SUNLOCK(fdp); + + return (copyout(&rights, uap->fcntlrightsp, sizeof(rights))); } +/* + * For backward compatibility. + */ int -capability_chown(struct file *fp, uid_t uid, gid_t gid, - struct ucred *active_cred, struct thread *td) +sys_cap_new(struct thread *td, struct cap_new_args *uap) { + struct filedesc *fdp; + cap_rights_t rights; + register_t newfd; + int error, fd; + + fd = uap->fd; + rights = uap->rights; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_RIGHTS(rights); + + if ((rights & ~CAP_ALL) != 0) + return (EINVAL); + + fdp = td->td_proc->p_fd; + FILEDESC_SLOCK(fdp); + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_SUNLOCK(fdp); + return (EBADF); + } + error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); + FILEDESC_SUNLOCK(fdp); + if (error != 0) + return (error); + + error = do_dup(td, 0, fd, 0, &newfd); + if (error != 0) + return (error); - panic("capability_chown"); + FILEDESC_XLOCK(fdp); + /* + * We don't really care about the race between checking capability + * rights for the source descriptor and now. If capability rights + * were ok at that earlier point, the process had this descriptor + * with those rights, so we don't increase them in security sense, + * the process might have done the cap_new(2) a bit earlier to get + * the same effect. + */ + fdp->fd_ofiles[newfd].fde_rights = rights; + if ((rights & CAP_IOCTL) == 0) { + free(fdp->fd_ofiles[newfd].fde_ioctls, M_TEMP); + fdp->fd_ofiles[newfd].fde_ioctls = NULL; + fdp->fd_ofiles[newfd].fde_nioctls = 0; + } + if ((rights & CAP_FCNTL) == 0) + fdp->fd_ofiles[newfd].fde_fcntls = 0; + FILEDESC_XUNLOCK(fdp); + + td->td_retval[0] = newfd; + + return (0); } #else /* !CAPABILITIES */ @@ -524,42 +567,54 @@ capability_chown(struct file *fp, uid_t uid, gid_t gid, * Stub Capability functions for when options CAPABILITIES isn't compiled * into the kernel. */ + int -sys_cap_new(struct thread *td, struct cap_new_args *uap) +sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) { return (ENOSYS); } int -sys_cap_getrights(struct thread *td, struct cap_getrights_args *uap) +sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap) { return (ENOSYS); } int -cap_funwrap(struct file *fp_cap, cap_rights_t rights, struct file **fpp) +sys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap) { - KASSERT(fp_cap->f_type != DTYPE_CAPABILITY, - ("cap_funwrap: saw capability")); + return (ENOSYS); +} - *fpp = fp_cap; - return (0); +int +sys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) +{ + + return (ENOSYS); } int -cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp, - struct file **fpp) +sys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) { - KASSERT(fp_cap->f_type != DTYPE_CAPABILITY, - ("cap_funwrap_mmap: saw capability")); + return (ENOSYS); +} - *fpp = fp_cap; - *maxprotp = VM_PROT_ALL; - return (0); +int +sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) +{ + + return (ENOSYS); +} + +int +sys_cap_new(struct thread *td, struct cap_new_args *uap) +{ + + return (ENOSYS); } #endif /* CAPABILITIES */ diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index b97ff7f..39f33f3 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <sys/filio.h> #include <sys/fcntl.h> #include <sys/file.h> +#include <sys/lock.h> #include <sys/proc.h> #include <sys/signalvar.h> #include <sys/socketvar.h> @@ -244,7 +245,7 @@ kern_readv(struct thread *td, int fd, struct uio *auio) struct file *fp; int error; - error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp); + error = fget_read(td, fd, CAP_READ, &fp); if (error) return (error); error = dofileread(td, fd, fp, auio, (off_t)-1, 0); @@ -287,7 +288,7 @@ kern_preadv(td, fd, auio, offset) struct file *fp; int error; - error = fget_read(td, fd, CAP_READ, &fp); + error = fget_read(td, fd, CAP_PREAD, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -453,7 +454,7 @@ kern_writev(struct thread *td, int fd, struct uio *auio) struct file *fp; int error; - error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp); + error = fget_write(td, fd, CAP_WRITE, &fp); if (error) return (error); error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0); @@ -496,7 +497,7 @@ kern_pwritev(td, fd, auio, offset) struct file *fp; int error; - error = fget_write(td, fd, CAP_WRITE, &fp); + error = fget_write(td, fd, CAP_PWRITE, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -704,28 +705,60 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) { struct file *fp; struct filedesc *fdp; - int error; - int tmp; + int error, tmp, locked; AUDIT_ARG_FD(fd); AUDIT_ARG_CMD(com); - if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0) - return (error); - if ((fp->f_flag & (FREAD | FWRITE)) == 0) { - fdrop(fp, td); - return (EBADF); - } + fdp = td->td_proc->p_fd; + switch (com) { case FIONCLEX: + case FIOCLEX: FILEDESC_XLOCK(fdp); - fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE; - FILEDESC_XUNLOCK(fdp); + locked = LA_XLOCKED; + break; + default: +#ifdef CAPABILITIES + FILEDESC_SLOCK(fdp); + locked = LA_SLOCKED; +#else + locked = LA_UNLOCKED; +#endif + break; + } + +#ifdef CAPABILITIES + if ((fp = fget_locked(fdp, fd)) == NULL) { + error = EBADF; + goto out; + } + if ((error = cap_ioctl_check(fdp, fd, com)) != 0) { + fp = NULL; /* fhold() was not called yet */ + goto out; + } + fhold(fp); + if (locked == LA_SLOCKED) { + FILEDESC_SUNLOCK(fdp); + locked = LA_UNLOCKED; + } +#else + if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0) { + fp = NULL; + goto out; + } +#endif + if ((fp->f_flag & (FREAD | FWRITE)) == 0) { + error = EBADF; + goto out; + } + + switch (com) { + case FIONCLEX: + fdp->fd_ofiles[fd].fde_flags &= ~UF_EXCLOSE; goto out; case FIOCLEX: - FILEDESC_XLOCK(fdp); - fdp->fd_ofileflags[fd] |= UF_EXCLOSE; - FILEDESC_XUNLOCK(fdp); + fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE; goto out; case FIONBIO: if ((tmp = *(int *)data)) @@ -745,7 +778,21 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) error = fo_ioctl(fp, com, data, td->td_ucred, td); out: - fdrop(fp, td); + switch (locked) { + case LA_XLOCKED: + FILEDESC_XUNLOCK(fdp); + break; +#ifdef CAPABILITIES + case LA_SLOCKED: + FILEDESC_SUNLOCK(fdp); + break; +#endif + default: + FILEDESC_UNLOCK_ASSERT(fdp); + break; + } + if (fp != NULL) + fdrop(fp, td); return (error); } @@ -1130,32 +1177,8 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events) static __inline int getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp) { - struct file *fp; -#ifdef CAPABILITIES - struct file *fp_fromcap; - int error; -#endif - if ((fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); -#ifdef CAPABILITIES - /* - * If the file descriptor is for a capability, test rights and use - * the file descriptor references by the capability. - */ - error = cap_funwrap(fp, CAP_POLL_EVENT, &fp_fromcap); - if (error) { - fdrop(fp, curthread); - return (error); - } - if (fp != fp_fromcap) { - fhold(fp_fromcap); - fdrop(fp, curthread); - fp = fp_fromcap; - } -#endif /* CAPABILITIES */ - *fpp = fp; - return (0); + return (fget_unlocked(fdp, fd, CAP_POLL_EVENT, 0, fpp, NULL)); } /* @@ -1349,13 +1372,14 @@ pollrescan(struct thread *td) /* If the selinfo wasn't cleared the event didn't fire. */ if (si != NULL) continue; - fp = fdp->fd_ofiles[fd->fd]; + fp = fdp->fd_ofiles[fd->fd].fde_file; #ifdef CAPABILITIES - if ((fp == NULL) - || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) { + if (fp == NULL || + cap_check(cap_rights(fdp, fd->fd), CAP_POLL_EVENT) != 0) #else - if (fp == NULL) { + if (fp == NULL) #endif + { fd->revents = POLLNVAL; n++; continue; @@ -1408,9 +1432,8 @@ pollscan(td, fds, nfd) u_int nfd; { struct filedesc *fdp = td->td_proc->p_fd; - int i; struct file *fp; - int n = 0; + int i, n = 0; FILEDESC_SLOCK(fdp); for (i = 0; i < nfd; i++, fds++) { @@ -1420,13 +1443,15 @@ pollscan(td, fds, nfd) } else if (fds->fd < 0) { fds->revents = 0; } else { - fp = fdp->fd_ofiles[fds->fd]; + fp = fdp->fd_ofiles[fds->fd].fde_file; #ifdef CAPABILITIES - if ((fp == NULL) - || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) { + if (fp == NULL || + cap_check(cap_rights(fdp, fds->fd), + CAP_POLL_EVENT) != 0) #else - if (fp == NULL) { + if (fp == NULL) #endif + { fds->revents = POLLNVAL; n++; } else { diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 96f2400..e066014 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ const char *syscallnames[] = { @@ -522,7 +522,7 @@ const char *syscallnames[] = { "shmctl", /* 512 = shmctl */ "lpathconf", /* 513 = lpathconf */ "cap_new", /* 514 = cap_new */ - "cap_getrights", /* 515 = cap_getrights */ + "cap_rights_get", /* 515 = cap_rights_get */ "cap_enter", /* 516 = cap_enter */ "cap_getmode", /* 517 = cap_getmode */ "pdfork", /* 518 = pdfork */ @@ -540,4 +540,9 @@ const char *syscallnames[] = { "posix_fallocate", /* 530 = posix_fallocate */ "posix_fadvise", /* 531 = posix_fadvise */ "wait6", /* 532 = wait6 */ + "cap_rights_limit", /* 533 = cap_rights_limit */ + "cap_ioctls_limit", /* 534 = cap_ioctls_limit */ + "cap_ioctls_get", /* 535 = cap_ioctls_get */ + "cap_fcntls_limit", /* 536 = cap_fcntls_limit */ + "cap_fcntls_get", /* 537 = cap_fcntls_get */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 148dea3..1a89010 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -917,7 +917,7 @@ struct shmid_ds *buf); } 513 AUE_LPATHCONF STD { int lpathconf(char *path, int name); } 514 AUE_CAP_NEW STD { int cap_new(int fd, uint64_t rights); } -515 AUE_CAP_GETRIGHTS STD { int cap_getrights(int fd, \ +515 AUE_CAP_RIGHTS_GET STD { int cap_rights_get(int fd, \ uint64_t *rightsp); } 516 AUE_CAP_ENTER STD { int cap_enter(void); } 517 AUE_CAP_GETMODE STD { int cap_getmode(u_int *modep); } @@ -955,5 +955,15 @@ int *status, int options, \ struct __wrusage *wrusage, \ siginfo_t *info); } +533 AUE_CAP_RIGHTS_LIMIT STD { int cap_rights_limit(int fd, \ + uint64_t rights); } +534 AUE_CAP_IOCTLS_LIMIT STD { int cap_ioctls_limit(int fd, \ + const u_long *cmds, size_t ncmds); } +535 AUE_CAP_IOCTLS_GET STD { ssize_t cap_ioctls_get(int fd, \ + u_long *cmds, size_t maxcmds); } +536 AUE_CAP_FCNTLS_LIMIT STD { int cap_fcntls_limit(int fd, \ + uint32_t fcntlrights); } +537 AUE_CAP_FCNTLS_GET STD { int cap_fcntls_get(int fd, \ + uint32_t *fcntlrightsp); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index c755f92..d811da2 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3134,9 +3134,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } - /* cap_getrights */ + /* cap_rights_get */ case 515: { - struct cap_getrights_args *p = params; + struct cap_rights_get_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->rightsp; /* uint64_t * */ *n_args = 2; @@ -3286,6 +3286,48 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 6; break; } + /* cap_rights_limit */ + case 533: { + struct cap_rights_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = p->rights; /* uint64_t */ + *n_args = 2; + break; + } + /* cap_ioctls_limit */ + case 534: { + struct cap_ioctls_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* const u_long * */ + uarg[2] = p->ncmds; /* size_t */ + *n_args = 3; + break; + } + /* cap_ioctls_get */ + case 535: { + struct cap_ioctls_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* u_long * */ + uarg[2] = p->maxcmds; /* size_t */ + *n_args = 3; + break; + } + /* cap_fcntls_limit */ + case 536: { + struct cap_fcntls_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = p->fcntlrights; /* uint32_t */ + *n_args = 2; + break; + } + /* cap_fcntls_get */ + case 537: { + struct cap_fcntls_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->fcntlrightsp; /* uint32_t * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -8477,7 +8519,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* cap_getrights */ + /* cap_rights_get */ case 515: switch(ndx) { case 0: @@ -8745,6 +8787,77 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* cap_rights_limit */ + case 533: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint64_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_limit */ + case 534: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const u_long *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_get */ + case 535: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "u_long *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* cap_fcntls_limit */ + case 536: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* cap_fcntls_get */ + case 537: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint32_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -10556,7 +10669,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* cap_getrights */ + /* cap_rights_get */ case 515: if (ndx == 0 || ndx == 1) p = "int"; @@ -10638,6 +10751,31 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* cap_rights_limit */ + case 533: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_ioctls_limit */ + case 534: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_ioctls_get */ + case 535: + if (ndx == 0 || ndx == 1) + p = "ssize_t"; + break; + /* cap_fcntls_limit */ + case 536: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* cap_fcntls_get */ + case 537: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 5c7b753..02eccd7 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1840,23 +1840,15 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd, int error, ref; /* Validate the file descriptor. */ - if ((fdp = p->p_fd) == NULL) - return (EBADF); - - fp = fget_unlocked(fdp, fd); - if (fp == NULL) - return (EBADF); + fdp = p->p_fd; + error = fget_unlocked(fdp, fd, CAP_TTYHOOK, 0, &fp, NULL); + if (error != 0) + return (error); if (fp->f_ops == &badfileops) { error = EBADF; goto done1; } -#ifdef CAPABILITIES - error = cap_funwrap(fp, CAP_TTYHOOK, &fp); - if (error) - goto done1; -#endif - /* * Make sure the vnode is bound to a character device. * Unlocked check for the vnode type is ok there, because we diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 9da464c..2d18e77 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -45,6 +45,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include <sys/param.h> @@ -2032,8 +2033,8 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, &mqueueops); FILEDESC_XLOCK(fdp); - if (fdp->fd_ofiles[fd] == fp) - fdp->fd_ofileflags[fd] |= UF_EXCLOSE; + if (fdp->fd_ofiles[fd].fde_file == fp) + fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); td->td_retval[0] = fd; fdrop(fp, td); @@ -2275,11 +2276,13 @@ again: error = EBADF; goto out; } - error = cap_funwrap(fp2, CAP_POLL_EVENT, &fp2); +#ifdef CAPABILITIES + error = cap_check(cap_rights(fdp, uap->mqd), CAP_POLL_EVENT); if (error) { FILEDESC_SUNLOCK(fdp); goto out; } +#endif if (fp2 != fp) { FILEDESC_SUNLOCK(fdp); error = EBADF; diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index c219844..2de3409 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -579,8 +579,8 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode, finit(fp, FREAD | FWRITE, DTYPE_SEM, ks, &ksem_ops); FILEDESC_XLOCK(fdp); - if (fdp->fd_ofiles[fd] == fp) - fdp->fd_ofileflags[fd] |= UF_EXCLOSE; + if (fdp->fd_ofiles[fd].fde_file == fp) + fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); fdrop(fp, td); diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 3b43f8f..fc33de5 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -630,8 +630,8 @@ sys_shm_open(struct thread *td, struct shm_open_args *uap) finit(fp, FFLAGS(uap->flags & O_ACCMODE), DTYPE_SHM, shmfd, &shm_ops); FILEDESC_XLOCK(fdp); - if (fdp->fd_ofiles[fd] == fp) - fdp->fd_ofileflags[fd] |= UF_EXCLOSE; + if (fdp->fd_ofiles[fd].fde_file == fp) + fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE; FILEDESC_XUNLOCK(fdp); td->td_retval[0] = fd; fdrop(fp, td); diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index ba05d0e..eca171c 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -122,38 +122,20 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0, "Number of sendfile(2) sf_bufs in use"); /* - * Convert a user file descriptor to a kernel file entry and check that, if - * it is a capability, the right rights are present. A reference on the file - * entry is held upon returning. + * Convert a user file descriptor to a kernel file entry and check if required + * capability rights are present. + * A reference on the file entry is held upon returning. */ static int getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights, struct file **fpp, u_int *fflagp) { struct file *fp; -#ifdef CAPABILITIES - struct file *fp_fromcap; int error; -#endif - if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); -#ifdef CAPABILITIES - /* - * If the file descriptor is for a capability, test rights and use - * the file descriptor referenced by the capability. - */ - error = cap_funwrap(fp, rights, &fp_fromcap); - if (error) { - fdrop(fp, curthread); + error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL); + if (error != 0) return (error); - } - if (fp != fp_fromcap) { - fhold(fp_fromcap); - fdrop(fp, curthread); - fp = fp_fromcap; - } -#endif /* CAPABILITIES */ if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, curthread); return (ENOTSOCK); @@ -766,7 +748,7 @@ kern_sendit(td, s, mp, flags, control, segflg) #endif AUDIT_ARG_FD(s); - rights = CAP_WRITE; + rights = CAP_SEND; if (mp->msg_name != NULL) { AUDIT_ARG_SOCKADDR(td, mp->msg_name); rights |= CAP_CONNECT; @@ -975,7 +957,7 @@ kern_recvit(td, s, mp, fromseg, controlp) *controlp = NULL; AUDIT_ARG_FD(s); - error = getsock_cap(td->td_proc->p_fd, s, CAP_READ, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_RECV, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1851,7 +1833,11 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap, * we send only the header/trailer and no payload data. */ AUDIT_ARG_FD(uap->fd); - if ((error = fgetvp_read(td, uap->fd, CAP_READ, &vp)) != 0) + /* + * sendfile(2) can start at any offset within a file so we require + * CAP_READ+CAP_SEEK = CAP_PREAD. + */ + if ((error = fgetvp_read(td, uap->fd, CAP_PREAD, &vp)) != 0) goto out; vn_lock(vp, LK_SHARED | LK_RETRY); if (vp->v_type == VREG) { @@ -1887,7 +1873,7 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap, * The socket must be a stream socket and connected. * Remember if it a blocking or non-blocking socket. */ - if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_WRITE, + if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SEND, &sock_fp, NULL)) != 0) goto out; so = sock_fp->f_data; @@ -2424,7 +2410,7 @@ sys_sctp_generic_sendmsg (td, uap) u_sinfo = &sinfo; } - rights = CAP_WRITE; + rights = CAP_SEND; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { @@ -2535,7 +2521,7 @@ sys_sctp_generic_sendmsg_iov(td, uap) return (error); u_sinfo = &sinfo; } - rights = CAP_WRITE; + rights = CAP_SEND; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { @@ -2659,7 +2645,7 @@ sys_sctp_generic_recvmsg(td, uap) #endif AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_READ, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_RECV, &fp, NULL); if (error) { return (error); } diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index a6c308f..dcfd009 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -279,7 +279,7 @@ static void unp_drop(struct unpcb *, int); static void unp_gc(__unused void *, int); static void unp_scan(struct mbuf *, void (*)(struct file *)); static void unp_discard(struct file *); -static void unp_freerights(struct file **, int); +static void unp_freerights(struct filedescent *, int); static void unp_init(void); static int unp_internalize(struct mbuf **, struct thread *); static void unp_internalize_fp(struct file *); @@ -1642,14 +1642,14 @@ unp_drop(struct unpcb *unp, int errno) } static void -unp_freerights(struct file **rp, int fdcount) +unp_freerights(struct filedescent *fde, int fdcount) { - int i; struct file *fp; + int i; - for (i = 0; i < fdcount; i++) { - fp = *rp; - *rp++ = NULL; + for (i = 0; i < fdcount; i++, fde++) { + fp = fde->fde_file; + bzero(fde, sizeof(*fde)); unp_discard(fp); } } @@ -1661,8 +1661,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) struct cmsghdr *cm = mtod(control, struct cmsghdr *); int i; int *fdp; - struct file **rp; - struct file *fp; + struct filedesc *fdesc = td->td_proc->p_fd; + struct filedescent *fde, *fdep; void *data; socklen_t clen = control->m_len, datalen; int error, newfds; @@ -1683,20 +1683,20 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { - newfds = datalen / sizeof(struct file *); - rp = data; + newfds = datalen / sizeof(*fdep); + fdep = data; /* If we're not outputting the descriptors free them. */ if (error || controlp == NULL) { - unp_freerights(rp, newfds); + unp_freerights(fdep, newfds); goto next; } - FILEDESC_XLOCK(td->td_proc->p_fd); + FILEDESC_XLOCK(fdesc); /* if the new FD's will not fit free them. */ if (!fdavail(td, newfds)) { - FILEDESC_XUNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(fdesc); error = EMSGSIZE; - unp_freerights(rp, newfds); + unp_freerights(fdep, newfds); goto next; } @@ -1710,23 +1710,24 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) *controlp = sbcreatecontrol(NULL, newlen, SCM_RIGHTS, SOL_SOCKET); if (*controlp == NULL) { - FILEDESC_XUNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(fdesc); error = E2BIG; - unp_freerights(rp, newfds); + unp_freerights(fdep, newfds); goto next; } fdp = (int *) CMSG_DATA(mtod(*controlp, struct cmsghdr *)); - for (i = 0; i < newfds; i++) { + for (i = 0; i < newfds; i++, fdep++, fdp++) { if (fdalloc(td, 0, &f)) panic("unp_externalize fdalloc failed"); - fp = *rp++; - td->td_proc->p_fd->fd_ofiles[f] = fp; - unp_externalize_fp(fp); - *fdp++ = f; + fde = &fdesc->fd_ofiles[f]; + fde->fde_file = fdep->fde_file; + filecaps_copy(&fdep->fde_caps, &fde->fde_caps); + unp_externalize_fp(fde->fde_file); + *fdp = f; } - FILEDESC_XUNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(fdesc); } else { /* We can just copy anything else across. */ if (error || controlp == NULL) @@ -1797,11 +1798,11 @@ unp_internalize(struct mbuf **controlp, struct thread *td) { struct mbuf *control = *controlp; struct proc *p = td->td_proc; - struct filedesc *fdescp = p->p_fd; + struct filedesc *fdesc = p->p_fd; struct bintime *bt; struct cmsghdr *cm = mtod(control, struct cmsghdr *); struct cmsgcred *cmcred; - struct file **rp; + struct filedescent *fde, *fdep; struct file *fp; struct timeval *tv; int i, fd, *fdp; @@ -1854,18 +1855,17 @@ unp_internalize(struct mbuf **controlp, struct thread *td) * files. If not, reject the entire operation. */ fdp = data; - FILEDESC_SLOCK(fdescp); + FILEDESC_SLOCK(fdesc); for (i = 0; i < oldfds; i++) { fd = *fdp++; - if (fd < 0 || fd >= fdescp->fd_nfiles || - fdescp->fd_ofiles[fd] == NULL) { - FILEDESC_SUNLOCK(fdescp); + if (fget_locked(fdesc, fd) == NULL) { + FILEDESC_SUNLOCK(fdesc); error = EBADF; goto out; } - fp = fdescp->fd_ofiles[fd]; + fp = fdesc->fd_ofiles[fd].fde_file; if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { - FILEDESC_SUNLOCK(fdescp); + FILEDESC_SUNLOCK(fdesc); error = EOPNOTSUPP; goto out; } @@ -1874,25 +1874,26 @@ unp_internalize(struct mbuf **controlp, struct thread *td) /* * Now replace the integer FDs with pointers to the - * associated global file table entry.. + * file structure and capability rights. */ - newlen = oldfds * sizeof(struct file *); + newlen = oldfds * sizeof(*fdep); *controlp = sbcreatecontrol(NULL, newlen, SCM_RIGHTS, SOL_SOCKET); if (*controlp == NULL) { - FILEDESC_SUNLOCK(fdescp); + FILEDESC_SUNLOCK(fdesc); error = E2BIG; goto out; } fdp = data; - rp = (struct file **) + fdep = (struct filedescent *) CMSG_DATA(mtod(*controlp, struct cmsghdr *)); - for (i = 0; i < oldfds; i++) { - fp = fdescp->fd_ofiles[*fdp++]; - *rp++ = fp; - unp_internalize_fp(fp); + for (i = 0; i < oldfds; i++, fdep++, fdp++) { + fde = &fdesc->fd_ofiles[*fdp]; + fdep->fde_file = fde->fde_file; + filecaps_copy(&fde->fde_caps, &fdep->fde_caps); + unp_internalize_fp(fdep->fde_file); } - FILEDESC_SUNLOCK(fdescp); + FILEDESC_SUNLOCK(fdesc); break; case SCM_TIMESTAMP: @@ -2252,7 +2253,7 @@ static void unp_scan(struct mbuf *m0, void (*op)(struct file *)) { struct mbuf *m; - struct file **rp; + struct filedescent *fdep; struct cmsghdr *cm; void *data; int i; @@ -2277,10 +2278,10 @@ unp_scan(struct mbuf *m0, void (*op)(struct file *)) if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { - qfds = datalen / sizeof (struct file *); - rp = data; - for (i = 0; i < qfds; i++) - (*op)(*rp++); + qfds = datalen / sizeof(*fdep); + fdep = data; + for (i = 0; i < qfds; i++, fdep++) + (*op)(fdep->fde_file); } if (CMSG_SPACE(datalen) < clen) { diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 28b3175..cafe440 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -1594,16 +1594,16 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, fd = aiocbe->uaiocb.aio_fildes; switch (opcode) { case LIO_WRITE: - error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp); + error = fget_write(td, fd, CAP_PWRITE, &fp); break; case LIO_READ: - error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp); + error = fget_read(td, fd, CAP_PREAD, &fp); break; case LIO_SYNC: error = fget(td, fd, CAP_FSYNC, &fp); break; case LIO_NOP: - error = fget(td, fd, 0, &fp); + error = fget(td, fd, CAP_NONE, &fp); break; default: error = EINVAL; diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 72a4afb..ed071b0 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -856,8 +856,12 @@ vop_stdvptocnp(struct vop_vptocnp_args *ap) error = ENOMEM; goto out; } - bcopy(dp->d_name, buf + i, dp->d_namlen); - error = 0; + if (dp->d_namlen == 1 && dp->d_name[0] == '.') { + error = ENOENT; + } else { + bcopy(dp->d_name, buf + i, dp->d_namlen); + error = 0; + } goto out; } } while (len > 0 || !eofflag); diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index fbde152..94d11f2 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -227,17 +227,18 @@ namei(struct nameidata *ndp) AUDIT_ARG_ATFD2(ndp->ni_dirfd); error = fgetvp_rights(td, ndp->ni_dirfd, ndp->ni_rightsneeded | CAP_LOOKUP, - &(ndp->ni_baserights), &dp); + &ndp->ni_filecaps, &dp); #ifdef CAPABILITIES /* - * Lookups relative to a capability must also be + * If file descriptor doesn't have all rights, + * all lookups relative to it must also be * strictly relative. - * - * Note that a capability with rights CAP_MASK_VALID - * is treated exactly like a regular file descriptor. */ - if (ndp->ni_baserights != CAP_MASK_VALID) + if (ndp->ni_filecaps.fc_rights != CAP_ALL || + ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || + ndp->ni_filecaps.fc_nioctls != -1) { ndp->ni_strictrelative = 1; + } #endif } if (error != 0 || dp != NULL) { diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 4232935..fc78235 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -971,6 +971,8 @@ flags_to_rights(int flags) /* FALLTHROUGH */ case O_WRONLY: rights |= CAP_WRITE; + if (!(flags & O_APPEND)) + rights |= CAP_SEEK; break; } } @@ -1144,19 +1146,22 @@ success: * If we haven't already installed the FD (for dupfdopen), do so now. */ if (indx == -1) { + struct filecaps *fcaps; + #ifdef CAPABILITIES - if (nd.ni_strictrelative == 1) { - /* - * We are doing a strict relative lookup; wrap the - * result in a capability. - */ - if ((error = kern_capwrap(td, fp, nd.ni_baserights, - &indx)) != 0) - goto bad; - } else + if (nd.ni_strictrelative == 1) + fcaps = &nd.ni_filecaps; + else #endif - if ((error = finstall(td, fp, &indx, flags)) != 0) - goto bad; + fcaps = NULL; + error = finstall(td, fp, &indx, flags, fcaps); + /* On success finstall() consumes fcaps. */ + if (error != 0) { + filecaps_free(&nd.ni_filecaps); + goto bad; + } + } else { + filecaps_free(&nd.ni_filecaps); } /* @@ -1280,7 +1285,7 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - pathseg, path, fd, CAP_MKNOD, td); + pathseg, path, fd, CAP_MKNODAT, td); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; @@ -1400,7 +1405,7 @@ kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - pathseg, path, fd, CAP_MKFIFO, td); + pathseg, path, fd, CAP_MKFIFOAT, td); if ((error = namei(&nd)) != 0) return (error); if (nd.ni_vp != NULL) { @@ -1554,7 +1559,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, return (error); } NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2, - segflg, path2, fd2, CAP_CREATE, td); + segflg, path2, fd2, CAP_LINKAT, td); if ((error = namei(&nd)) == 0) { if (nd.ni_vp != NULL) { if (nd.ni_dvp == nd.ni_vp) @@ -1647,7 +1652,7 @@ kern_symlinkat(struct thread *td, char *path1, int fd, char *path2, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - segflg, path2, fd, CAP_CREATE, td); + segflg, path2, fd, CAP_SYMLINKAT, td); if ((error = namei(&nd)) != 0) goto out; if (nd.ni_vp) { @@ -1799,7 +1804,7 @@ kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, - pathseg, path, fd, CAP_DELETE, td); + pathseg, path, fd, CAP_UNLINKAT, td); if ((error = namei(&nd)) != 0) return (error == EINVAL ? EPERM : error); vp = nd.ni_vp; @@ -2634,9 +2639,9 @@ setfflags(td, vp, flags) if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) return (error); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VATTR_NULL(&vattr); vattr.va_flags = flags; + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef MAC error = mac_vnode_check_setflags(td->td_ucred, vp, vattr.va_flags); if (error == 0) @@ -3503,10 +3508,10 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, bwillwrite(); #ifdef MAC NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | - AUDITVNODE1, pathseg, old, oldfd, CAP_DELETE, td); + AUDITVNODE1, pathseg, old, oldfd, CAP_RENAMEAT, td); #else NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, - pathseg, old, oldfd, CAP_DELETE, td); + pathseg, old, oldfd, CAP_RENAMEAT, td); #endif if ((error = namei(&fromnd)) != 0) @@ -3528,7 +3533,7 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, goto out1; } NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | - SAVESTART | AUDITVNODE2, pathseg, new, newfd, CAP_CREATE, td); + SAVESTART | AUDITVNODE2, pathseg, new, newfd, CAP_LINKAT, td); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&tond)) != 0) { @@ -3551,6 +3556,18 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, error = EISDIR; goto out; } +#ifdef CAPABILITIES + if (newfd != AT_FDCWD) { + /* + * If the target already exists we require CAP_UNLINKAT + * from 'newfd'. + */ + error = cap_check(tond.ni_filecaps.fc_rights, + CAP_UNLINKAT); + if (error != 0) + goto out; + } +#endif } if (fvp == tdvp) { error = EINVAL; @@ -3651,7 +3668,7 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1, - segflg, path, fd, CAP_MKDIR, td); + segflg, path, fd, CAP_MKDIRAT, td); nd.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&nd)) != 0) return (error); @@ -3735,7 +3752,7 @@ kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg) restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, - pathseg, path, fd, CAP_RMDIR, td); + pathseg, path, fd, CAP_UNLINKAT, td); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; @@ -3988,8 +4005,7 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, if (count > IOSIZE_MAX) return (EINVAL); auio.uio_resid = count; - if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ | CAP_SEEK, - &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -4152,33 +4168,14 @@ out: * entry is held upon returning. */ int -getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, - struct file **fpp) +getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, struct file **fpp) { struct file *fp; -#ifdef CAPABILITIES - struct file *fp_fromcap; int error; -#endif - if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); -#ifdef CAPABILITIES - /* - * If the file descriptor is for a capability, test rights and use the - * file descriptor referenced by the capability. - */ - error = cap_funwrap(fp, rights, &fp_fromcap); - if (error) { - fdrop(fp, curthread); + error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL); + if (error != 0) return (error); - } - if (fp != fp_fromcap) { - fhold(fp_fromcap); - fdrop(fp, curthread); - fp = fp_fromcap; - } -#endif /* CAPABILITIES */ /* * The file could be not of the vnode type, or it may be not @@ -4362,7 +4359,7 @@ sys_fhopen(td, uap) goto bad; } - error = finstall(td, fp, &indx, fmode); + error = finstall(td, fp, &indx, fmode, NULL); bad: fdrop(fp, td); td->td_retval[0] = indx; @@ -4615,7 +4612,7 @@ kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, return (EINVAL); } /* XXX: CAP_POSIX_FADVISE? */ - error = fget(td, fd, 0, &fp); + error = fget(td, fd, CAP_NONE, &fp); if (error != 0) goto out; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 271e022..d367340 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1861,7 +1861,6 @@ vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td) { struct vnode *vp; - int error; vp = fp->f_vnode; #ifdef AUDIT @@ -1869,8 +1868,7 @@ vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, AUDIT_ARG_VNODE1(vp); VOP_UNLOCK(vp, 0); #endif - error = setfmode(td, active_cred, vp, mode); - return (error); + return (setfmode(td, active_cred, vp, mode)); } int @@ -1878,7 +1876,6 @@ vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td) { struct vnode *vp; - int error; vp = fp->f_vnode; #ifdef AUDIT @@ -1886,8 +1883,7 @@ vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, AUDIT_ARG_VNODE1(vp); VOP_UNLOCK(vp, 0); #endif - error = setfown(td, active_cred, vp, uid, gid); - return (error); + return (setfown(td, active_cred, vp, uid, gid)); } void diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c index 50f4f24..1dc3e7a 100644 --- a/sys/mips/mips/tick.c +++ b/sys/mips/mips/tick.c @@ -217,22 +217,17 @@ DELAY(int n) } static int -clock_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; - if (period != NULL) { - div = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - div += et->et_frequency * period->sec; + if (period != 0) { + div = (et->et_frequency * period) >> 32; } else div = 0; - if (first != NULL) { - fdiv = (et->et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += et->et_frequency * first->sec; - } else + if (first != 0) + fdiv = (et->et_frequency * first) >> 32; + else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; @@ -361,11 +356,8 @@ clock_attach(device_t dev) ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = 0x00004000LLU << 32; /* To be safe. */ - sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; diff --git a/sys/mips/nlm/tick.c b/sys/mips/nlm/tick.c index 09f3bb6..b5a8c36 100644 --- a/sys/mips/nlm/tick.c +++ b/sys/mips/nlm/tick.c @@ -222,22 +222,17 @@ DELAY(int n) } static int -clock_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; - if (period != NULL) { - div = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - div += et->et_frequency * period->sec; - } else + if (period != 0) + div = (et->et_frequency * period) >> 32; + else div = 0; - if (first != NULL) { - fdiv = (et->et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += et->et_frequency * first->sec; - } else + if (first != 0) + fdiv = (et->et_frequency * first) >> 32; + else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; @@ -357,11 +352,8 @@ clock_attach(device_t dev) sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = 0x00004000LLU << 32; /* To be safe. */ - sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; diff --git a/sys/mips/rmi/tick.c b/sys/mips/rmi/tick.c index 39f0a04..adc8c89 100644 --- a/sys/mips/rmi/tick.c +++ b/sys/mips/rmi/tick.c @@ -219,22 +219,17 @@ DELAY(int n) } static int -clock_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; - if (period != NULL) { - div = (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - div += et->et_frequency * period->sec; - } else + if (period != 0) + div = (et->et_frequency * period) >> 32; + else div = 0; - if (first != NULL) { - fdiv = (et->et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += et->et_frequency * first->sec; - } else + if (first != 0) + fdiv = (et->et_frequency * first) >> 32; + else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; @@ -351,11 +346,8 @@ clock_attach(device_t dev) ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = 0x00004000LLU << 32; /* To be safe. */ - sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency; - sc->et.et_max_period.frac = - ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; + sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ + sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; diff --git a/sys/modules/ixgbe/Makefile b/sys/modules/ixgbe/Makefile index 1bc64a0..6abdf7a 100644 --- a/sys/modules/ixgbe/Makefile +++ b/sys/modules/ixgbe/Makefile @@ -4,7 +4,7 @@ .PATH: ${.CURDIR}/../../dev/ixgbe -KMOD = ixgbe +KMOD = if_ixgbe SRCS = device_if.h bus_if.h pci_if.h SRCS += opt_inet.h opt_inet6.h SRCS += ixgbe.c ixv.c diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c index dfedd88..a09d74d 100644 --- a/sys/netsmb/smb_dev.c +++ b/sys/netsmb/smb_dev.c @@ -399,9 +399,7 @@ nsmb_getfp(struct filedesc* fdp, int fd, int flag) struct file* fp; FILEDESC_SLOCK(fdp); - if (fd < 0 || fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL || - (fp->f_flag & flag) == 0) { + if ((fp = fget_locked(fdp, fd)) == NULL || (fp->f_flag & flag) == 0) { FILEDESC_SUNLOCK(fdp); return (NULL); } diff --git a/sys/nfsserver/nfs_srvkrpc.c b/sys/nfsserver/nfs_srvkrpc.c index 64f2aaa..6b3a6b7 100644 --- a/sys/nfsserver/nfs_srvkrpc.c +++ b/sys/nfsserver/nfs_srvkrpc.c @@ -174,7 +174,8 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap) sizeof(addsockarg)); if (error) return (error); - if ((error = fget(td, addsockarg.sock, CAP_SOCK_ALL, &fp)) != 0) + error = fget(td, addsockarg.sock, CAP_SOCK_SERVER, &fp); + if (error) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/ofed/include/linux/file.h b/sys/ofed/include/linux/file.h index cbeec39..b9bd8b1 100644 --- a/sys/ofed/include/linux/file.h +++ b/sys/ofed/include/linux/file.h @@ -47,7 +47,8 @@ linux_fget(unsigned int fd) { struct file *file; - file = fget_unlocked(curthread->td_proc->p_fd, fd); + if (fget_unlocked(curthread->td_proc->p_fd, fd, 0, 0, &file, NULL) != 0) + return (NULL); return (struct linux_file *)file->f_data; } @@ -69,8 +70,7 @@ put_unused_fd(unsigned int fd) { struct file *file; - file = fget_unlocked(curthread->td_proc->p_fd, fd); - if (file == NULL) + if (fget_unlocked(curthread->td_proc->p_fd, fd, 0, 0, &file, NULL) != 0) return; fdclose(curthread->td_proc->p_fd, file, fd, curthread); } @@ -80,7 +80,8 @@ fd_install(unsigned int fd, struct linux_file *filp) { struct file *file; - file = fget_unlocked(curthread->td_proc->p_fd, fd); + if (fget_unlocked(curthread->td_proc->p_fd, fd, 0, 0, &file, NULL) != 0) + file = NULL; filp->_file = file; finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops); } diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index 260e1a2..383897b 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -1146,7 +1146,7 @@ SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, #define STATE_SLEEPING 0x2 static void -cpu_idle_hlt(int busy) +cpu_idle_hlt(sbintime_t sbt) { int *state; @@ -1187,7 +1187,7 @@ cpu_idle_hlt(int busy) #define MWAIT_C4 0x30 static void -cpu_idle_mwait(int busy) +cpu_idle_mwait(sbintime_t sbt) { int *state; @@ -1210,7 +1210,7 @@ cpu_idle_mwait(int busy) } static void -cpu_idle_spin(int busy) +cpu_idle_spin(sbintime_t sbt) { int *state; int i; @@ -1230,11 +1230,12 @@ cpu_idle_spin(int busy) } } -void (*cpu_idle_fn)(int) = cpu_idle_hlt; +void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt; void cpu_idle(int busy) { + sbintime_t sbt = -1; CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", busy, curcpu); @@ -1252,11 +1253,11 @@ cpu_idle(int busy) /* If we have time - switch timers into idle mode. */ if (!busy) { critical_enter(); - cpu_idleclock(); + sbt = cpu_idleclock(); } /* Call main idle method. */ - cpu_idle_fn(busy); + cpu_idle_fn(sbt); /* Switch timers mack into active mode. */ if (!busy) { diff --git a/sys/powerpc/aim/clock.c b/sys/powerpc/aim/clock.c index 0bf7cfa..ae98d26 100644 --- a/sys/powerpc/aim/clock.c +++ b/sys/powerpc/aim/clock.c @@ -85,7 +85,7 @@ static u_long ticks_per_sec = 12500000; static u_long *decr_counts[MAXCPU]; static int decr_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period); + sbintime_t first, sbintime_t period); static int decr_et_stop(struct eventtimer *et); static timecounter_get_t decr_get_timecount; @@ -195,12 +195,8 @@ decr_tc_init(void) ET_FLAGS_PERCPU; decr_et.et_quality = 1000; decr_et.et_frequency = ticks_per_sec; - decr_et.et_min_period.sec = 0; - decr_et.et_min_period.frac = - ((0x00000002LLU << 32) / ticks_per_sec) << 32; - decr_et.et_max_period.sec = 0x7fffffffLLU / ticks_per_sec; - decr_et.et_max_period.frac = - ((0x7fffffffLLU << 32) / ticks_per_sec) << 32; + decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec; + decr_et.et_max_period = (0x7fffffffLLU << 32) / ticks_per_sec; decr_et.et_start = decr_et_start; decr_et.et_stop = decr_et_stop; decr_et.et_priv = NULL; @@ -212,24 +208,20 @@ decr_tc_init(void) */ static int decr_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) + sbintime_t first, sbintime_t period) { struct decr_state *s = DPCPU_PTR(decr_state); uint32_t fdiv; - if (period != NULL) { + if (period != 0) { s->mode = 1; - s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - s->div += decr_et.et_frequency * period->sec; + s->div = (decr_et.et_frequency * period) >> 32; } else { s->mode = 2; - s->div = 0x7fffffff; + s->div = 0; } - if (first != NULL) { - fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += decr_et.et_frequency * first->sec; + if (first != 0) { + fdiv = (decr_et.et_frequency * first) >> 32; } else fdiv = s->div; diff --git a/sys/powerpc/booke/clock.c b/sys/powerpc/booke/clock.c index 9958160..5827e73 100644 --- a/sys/powerpc/booke/clock.c +++ b/sys/powerpc/booke/clock.c @@ -88,7 +88,7 @@ static u_long *decr_counts[MAXCPU]; #define DIFF19041970 2082844800 static int decr_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period); + sbintime_t first, sbintime_t period); static int decr_et_stop(struct eventtimer *et); static timecounter_get_t decr_get_timecount; @@ -193,12 +193,8 @@ decr_tc_init(void) ET_FLAGS_PERCPU; decr_et.et_quality = 1000; decr_et.et_frequency = ticks_per_sec; - decr_et.et_min_period.sec = 0; - decr_et.et_min_period.frac = - ((0x00000002LLU << 32) / ticks_per_sec) << 32; - decr_et.et_max_period.sec = 0xfffffffeLLU / ticks_per_sec; - decr_et.et_max_period.frac = - ((0xfffffffeLLU << 32) / ticks_per_sec) << 32; + decr_et.et_min_period = (0x00000002LLU << 32) / ticks_per_sec; + decr_et.et_max_period = (0xfffffffeLLU << 32) / ticks_per_sec; decr_et.et_start = decr_et_start; decr_et.et_stop = decr_et_stop; decr_et.et_priv = NULL; @@ -209,26 +205,21 @@ decr_tc_init(void) * Event timer start method. */ static int -decr_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +decr_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct decr_state *s = DPCPU_PTR(decr_state); uint32_t fdiv, tcr; - if (period != NULL) { + if (period != 0) { s->mode = 1; - s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - s->div += decr_et.et_frequency * period->sec; + s->div = (decr_et.et_frequency * period) >> 32; } else { s->mode = 2; - s->div = 0xffffffff; + s->div = 0; } - if (first != NULL) { - fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += decr_et.et_frequency * first->sec; - } else + if (first != 0) + fdiv = (decr_et.et_frequency * first) >> 32; + else fdiv = s->div; tcr = mfspr(SPR_TCR); diff --git a/sys/powerpc/powerpc/cpu.c b/sys/powerpc/powerpc/cpu.c index d177c8b..d67f359 100644 --- a/sys/powerpc/powerpc/cpu.c +++ b/sys/powerpc/powerpc/cpu.c @@ -79,9 +79,9 @@ static void cpu_970_setup(int cpuid, uint16_t vers); static void cpu_booke_setup(int cpuid, uint16_t vers); int powerpc_pow_enabled; -void (*cpu_idle_hook)(void) = NULL; -static void cpu_idle_60x(void); -static void cpu_idle_booke(void); +void (*cpu_idle_hook)(sbintime_t) = NULL; +static void cpu_idle_60x(sbintime_t); +static void cpu_idle_booke(sbintime_t); struct cputab { const char *name; @@ -516,6 +516,7 @@ cpu_feature_bit(SYSCTL_HANDLER_ARGS) void cpu_idle(int busy) { + sbintime_t sbt = -1; #ifdef INVARIANTS if ((mfmsr() & PSL_EE) != PSL_EE) { @@ -531,9 +532,9 @@ cpu_idle(int busy) if (cpu_idle_hook != NULL) { if (!busy) { critical_enter(); - cpu_idleclock(); + sbt = cpu_idleclock(); } - cpu_idle_hook(); + cpu_idle_hook(sbt); if (!busy) { cpu_activeclock(); critical_exit(); @@ -551,7 +552,7 @@ cpu_idle_wakeup(int cpu) } static void -cpu_idle_60x(void) +cpu_idle_60x(sbintime_t sbt) { register_t msr; uint16_t vers; @@ -586,7 +587,7 @@ cpu_idle_60x(void) } static void -cpu_idle_booke(void) +cpu_idle_booke(sbintime_t sbt) { register_t msr; diff --git a/sys/powerpc/ps3/platform_ps3.c b/sys/powerpc/ps3/platform_ps3.c index 61ce873..207382d 100644 --- a/sys/powerpc/ps3/platform_ps3.c +++ b/sys/powerpc/ps3/platform_ps3.c @@ -70,7 +70,7 @@ static int ps3_smp_start_cpu(platform_t, struct pcpu *cpu); static struct cpu_group *ps3_smp_topo(platform_t); #endif static void ps3_reset(platform_t); -static void ps3_cpu_idle(void); +static void ps3_cpu_idle(sbintime_t); static platform_method_t ps3_methods[] = { PLATFORMMETHOD(platform_probe, ps3_probe), @@ -245,7 +245,7 @@ ps3_real_maxaddr(platform_t plat) } static void -ps3_cpu_idle(void) +ps3_cpu_idle(sbintime_t sbt) { lv1_pause(0); } diff --git a/sys/powerpc/wii/platform_wii.c b/sys/powerpc/wii/platform_wii.c index 2bb6022..bc35105 100644 --- a/sys/powerpc/wii/platform_wii.c +++ b/sys/powerpc/wii/platform_wii.c @@ -60,7 +60,7 @@ static void wii_mem_regions(platform_t, struct mem_region **, int *, struct mem_region **, int *); static unsigned long wii_timebase_freq(platform_t, struct cpuref *cpuref); static void wii_reset(platform_t); -static void wii_cpu_idle(void); +static void wii_cpu_idle(sbintime_t sbt); static platform_method_t wii_methods[] = { PLATFORMMETHOD(platform_probe, wii_probe), @@ -155,6 +155,6 @@ wii_reset(platform_t plat) } static void -wii_cpu_idle(void) +wii_cpu_idle(sbintime_t sbt) { } diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h index f43f6c8..733a3c7 100644 --- a/sys/security/audit/audit.h +++ b/sys/security/audit/audit.h @@ -115,6 +115,7 @@ void audit_arg_file(struct proc *p, struct file *fp); void audit_arg_argv(char *argv, int argc, int length); void audit_arg_envv(char *envv, int envc, int length); void audit_arg_rights(cap_rights_t rights); +void audit_arg_fcntl_rights(uint32_t fcntlrights); void audit_sysclose(struct thread *td, int fd); void audit_cred_copy(struct ucred *src, struct ucred *dest); void audit_cred_destroy(struct ucred *cred); @@ -241,6 +242,11 @@ void audit_thread_free(struct thread *td); audit_arg_rights((rights)); \ } while (0) +#define AUDIT_ARG_FCNTL_RIGHTS(fcntlrights) do { \ + if (AUDITING_TD(curthread)) \ + audit_arg_fcntl_rights((fcntlrights)); \ +} while (0) + #define AUDIT_ARG_RUID(ruid) do { \ if (AUDITING_TD(curthread)) \ audit_arg_ruid((ruid)); \ @@ -354,6 +360,7 @@ void audit_thread_free(struct thread *td); #define AUDIT_ARG_PROCESS(p) #define AUDIT_ARG_RGID(rgid) #define AUDIT_ARG_RIGHTS(rights) +#define AUDIT_ARG_FCNTL_RIGHTS(fcntlrights) #define AUDIT_ARG_RUID(ruid) #define AUDIT_ARG_SIGNUM(signum) #define AUDIT_ARG_SGID(sgid) diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c index 41d6b42..ec04b8b 100644 --- a/sys/security/audit/audit_arg.c +++ b/sys/security/audit/audit_arg.c @@ -871,6 +871,19 @@ audit_arg_rights(cap_rights_t rights) ARG_SET_VALID(ar, ARG_RIGHTS); } +void +audit_arg_fcntl_rights(uint32_t fcntlrights) +{ + struct kaudit_record *ar; + + ar = currecord(); + if (ar == NULL) + return; + + ar->k_ar.ar_arg_fcntl_rights = fcntlrights; + ARG_SET_VALID(ar, ARG_FCNTL_RIGHTS); +} + /* * The close() system call uses it's own audit call to capture the path/vnode * information because those pieces are not easily obtained within the system diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c index 8881cea..9c69b1e 100644 --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -1597,6 +1597,7 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) break; case AUE_CAP_NEW: + case AUE_CAP_RIGHTS_LIMIT: /* * XXXRW/XXXJA: Would be nice to audit socket/etc information. */ @@ -1607,13 +1608,25 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) } break; - case AUE_CAP_GETRIGHTS: + case AUE_CAP_FCNTLS_GET: + case AUE_CAP_IOCTLS_GET: + case AUE_CAP_IOCTLS_LIMIT: + case AUE_CAP_RIGHTS_GET: if (ARG_IS_VALID(kar, ARG_FD)) { tok = au_to_arg32(1, "fd", ar->ar_arg_fd); kau_write(rec, tok); } break; + case AUE_CAP_FCNTLS_LIMIT: + FD_VNODE1_TOKENS; + if (ARG_IS_VALID(kar, ARG_FCNTL_RIGHTS)) { + tok = au_to_arg32(2, "fcntlrights", + ar->ar_arg_fcntl_rights); + kau_write(rec, tok); + } + break; + case AUE_CAP_ENTER: case AUE_CAP_GETMODE: break; diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h index 10ccd5b..e23ba08 100644 --- a/sys/security/audit/audit_private.h +++ b/sys/security/audit/audit_private.h @@ -230,6 +230,7 @@ struct audit_record { int ar_arg_exitretval; struct sockaddr_storage ar_arg_sockaddr; cap_rights_t ar_arg_rights; + uint32_t ar_arg_fcntl_rights; char ar_jailname[MAXHOSTNAMELEN]; }; @@ -291,6 +292,7 @@ struct audit_record { #define ARG_ATFD1 0x0004000000000000ULL #define ARG_ATFD2 0x0008000000000000ULL #define ARG_RIGHTS 0x0010000000000000ULL +#define ARG_FCNTL_RIGHTS 0x0020000000000000ULL #define ARG_NONE 0x0000000000000000ULL #define ARG_ALL 0xFFFFFFFFFFFFFFFFULL diff --git a/sys/sparc64/pci/ofw_pcib.c b/sys/sparc64/pci/ofw_pcib.c index 69bdb72..7944237 100644 --- a/sys/sparc64/pci/ofw_pcib.c +++ b/sys/sparc64/pci/ofw_pcib.c @@ -47,8 +47,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <dev/ofw/openfirm.h> -#include <machine/bus.h> - #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcib_private.h> @@ -58,8 +56,12 @@ __FBSDID("$FreeBSD$"); #include <sparc64/pci/ofw_pci.h> #include <sparc64/pci/ofw_pcib_subr.h> +#define PCI_DEVID_ALI_M5249 0x524910b9 +#define PCI_VENDOR_PLX 0x10b5 + static device_probe_t ofw_pcib_probe; static device_attach_t ofw_pcib_attach; +static ofw_pci_setup_device_t ofw_pcib_setup_device; static device_method_t ofw_pcib_methods[] = { /* Device interface */ @@ -73,6 +75,7 @@ static device_method_t ofw_pcib_methods[] = { /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, ofw_pcib_gen_get_node), + DEVMETHOD(ofw_pci_setup_device, ofw_pcib_setup_device), DEVMETHOD_END }; @@ -81,7 +84,7 @@ static devclass_t pcib_devclass; DEFINE_CLASS_1(pcib, ofw_pcib_driver, ofw_pcib_methods, sizeof(struct ofw_pcib_gen_softc), pcib_driver); -EARLY_DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_driver, pcib_devclass, 0, 0, +EARLY_DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_driver, pcib_devclass, NULL, NULL, BUS_PASS_BUS); MODULE_DEPEND(ofw_pcib, pci, 1, 1, 1); @@ -104,7 +107,7 @@ ofw_pcib_probe(device_t dev) ISDTYPE(pbdtype, OFW_TYPE_PCIE) ? "e" : "", ISDTYPE(dtype, OFW_TYPE_PCIE) ? "e" : ""); device_set_desc_copy(dev, desc); - return (0); + return (BUS_PROBE_DEFAULT); } #undef ISDTYPE @@ -119,7 +122,6 @@ ofw_pcib_attach(device_t dev) sc = device_get_softc(dev); - /* Quirk handling */ switch (pci_get_devid(dev)) { /* * The ALi M5249 found in Fire-based machines by definition must me @@ -127,13 +129,46 @@ ofw_pcib_attach(device_t dev) * don't indicate this in the class code although the ISA I/O range * isn't included in their bridge decode. */ - case 0x524910b9: + case PCI_DEVID_ALI_M5249: sc->ops_pcib_sc.flags |= PCIB_SUBTRACTIVE; break; } + switch (pci_get_vendor(dev)) { + /* + * Concurrently write the primary and secondary bus numbers in order + * to work around a bug in PLX PEX 8114 causing the internal shadow + * copies of these not to be updated when setting them bytewise. + */ + case PCI_VENDOR_PLX: + pci_write_config(dev, PCIR_PRIBUS_1, + pci_read_config(dev, PCIR_SECBUS_1, 1) << 8 | + pci_read_config(dev, PCIR_PRIBUS_1, 1), 2); + break; + } + ofw_pcib_gen_setup(dev); pcib_attach_common(dev); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } + +static void +ofw_pcib_setup_device(device_t bus, device_t child) +{ + int i; + uint16_t reg; + + switch (pci_get_vendor(bus)) { + /* + * For PLX PEX 8532 issue 64 TLPs to the child from the downstream + * port to the child device in order to work around a hardware bug. + */ + case PCI_VENDOR_PLX: + for (i = 0, reg = 0; i < 64; i++) + reg |= pci_get_devid(child); + break; + } + + OFW_PCI_SETUP_DEVICE(device_get_parent(bus), child); +} diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index a44af7c..a6e1469 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/pcpu.h> #include <sys/reboot.h> #include <sys/rman.h> +#include <sys/sysctl.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_pci.h> @@ -94,7 +95,8 @@ static void psycho_intr_clear(void *); static driver_filter_t psycho_ue; static driver_filter_t psycho_ce; static driver_filter_t psycho_pci_bus; -static driver_filter_t psycho_powerfail; +static driver_filter_t psycho_powerdebug; +static driver_intr_t psycho_powerdown; static driver_intr_t psycho_overtemp; #ifdef PSYCHO_MAP_WAKEUP static driver_filter_t psycho_wakeup; @@ -159,9 +161,16 @@ static devclass_t psycho_devclass; DEFINE_CLASS_0(pcib, psycho_driver, psycho_methods, sizeof(struct psycho_softc)); -EARLY_DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, 0, 0, +EARLY_DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, NULL, NULL, BUS_PASS_BUS); +static SYSCTL_NODE(_hw, OID_AUTO, psycho, CTLFLAG_RD, 0, "psycho parameters"); + +static u_int psycho_powerfail = 1; +TUNABLE_INT("hw.psycho.powerfail", &psycho_powerfail); +SYSCTL_UINT(_hw_psycho, OID_AUTO, powerfail, CTLFLAG_RDTUN, &psycho_powerfail, + 0, "powerfail action (0: none, 1: shutdown (default), 2: debugger)"); + static SLIST_HEAD(, psycho_softc) psycho_softcs = SLIST_HEAD_INITIALIZER(psycho_softcs); @@ -612,13 +621,18 @@ psycho_attach(device_t dev) */ psycho_set_intr(sc, 1, PSR_UE_INT_MAP, psycho_ue, NULL); psycho_set_intr(sc, 2, PSR_CE_INT_MAP, psycho_ce, NULL); -#ifdef DEBUGGER_ON_POWERFAIL - psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, psycho_powerfail, - NULL); -#else - psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, NULL, - (driver_intr_t *)psycho_powerfail); -#endif + switch (psycho_powerfail) { + case 0: + break; + case 2: + psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, + psycho_powerdebug, NULL); + break; + default: + psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, NULL, + psycho_powerdown); + break; + } if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { /* * Hummingbirds/Sabres do not have the following two @@ -629,8 +643,8 @@ psycho_attach(device_t dev) * The spare hardware interrupt is used for the * over-temperature interrupt. */ - psycho_set_intr(sc, 4, PSR_SPARE_INT_MAP, - NULL, psycho_overtemp); + psycho_set_intr(sc, 4, PSR_SPARE_INT_MAP, NULL, + psycho_overtemp); #ifdef PSYCHO_MAP_WAKEUP /* * psycho_wakeup() doesn't do anything useful right @@ -837,27 +851,28 @@ psycho_pci_bus(void *arg) } static int -psycho_powerfail(void *arg) +psycho_powerdebug(void *arg __unused) { -#ifdef DEBUGGER_ON_POWERFAIL - struct psycho_softc *sc = arg; kdb_enter(KDB_WHY_POWERFAIL, "powerfail"); -#else + return (FILTER_HANDLED); +} + +static void +psycho_powerdown(void *arg __unused) +{ static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) - return (FILTER_HANDLED); + return; shutdown++; printf("Power Failure Detected: Shutting down NOW.\n"); - shutdown_nice(0); -#endif - return (FILTER_HANDLED); + shutdown_nice(RB_POWEROFF); } static void -psycho_overtemp(void *arg) +psycho_overtemp(void *arg __unused) { static int shutdown; diff --git a/sys/sparc64/pci/sbbc.c b/sys/sparc64/pci/sbbc.c index 491f653..218093f 100644 --- a/sys/sparc64/pci/sbbc.c +++ b/sys/sparc64/pci/sbbc.c @@ -299,7 +299,7 @@ static device_method_t sbbc_pci_methods[] = { static devclass_t sbbc_devclass; DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc)); -DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, 0, 0); +DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL); static int sbbc_pci_probe(device_t dev) @@ -358,8 +358,7 @@ sbbc_pci_attach(device_t dev) if (error != 0) device_printf(dev, "failed to attach UART device\n"); } else { - error = sbbc_parse_toc(rman_get_bustag(sc->sc_res), - rman_get_bushandle(sc->sc_res)); + error = sbbc_parse_toc(bst, bsh); if (error != 0) { device_printf(dev, "failed to parse TOC\n"); if (sbbc_console != 0) { @@ -609,7 +608,7 @@ static device_method_t sbbc_uart_sbbc_methods[] = { DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods, sizeof(struct uart_softc)); -DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, 0, 0); +DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL); static int sbbc_uart_sbbc_probe(device_t dev) diff --git a/sys/sparc64/sbus/sbus.c b/sys/sparc64/sbus/sbus.c index dbf1ccc..580624f 100644 --- a/sys/sparc64/sbus/sbus.c +++ b/sys/sparc64/sbus/sbus.c @@ -199,7 +199,7 @@ static driver_t sbus_driver = { static devclass_t sbus_devclass; -EARLY_DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0, +EARLY_DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, NULL, NULL, BUS_PASS_BUS); MODULE_DEPEND(sbus, nexus, 1, 1, 1); MODULE_VERSION(sbus, 1); @@ -898,7 +898,7 @@ sbus_get_devinfo(device_t bus, device_t child) * The same needs to be done to PCI controller drivers. */ static void -sbus_overtemp(void *arg) +sbus_overtemp(void *arg __unused) { static int shutdown; @@ -912,7 +912,7 @@ sbus_overtemp(void *arg) /* Try to shut down in time in case of power failure. */ static void -sbus_pwrfail(void *arg) +sbus_pwrfail(void *arg __unused) { static int shutdown; @@ -921,7 +921,7 @@ sbus_pwrfail(void *arg) return; shutdown++; printf("Power failure detected\nShutting down NOW.\n"); - shutdown_nice(0); + shutdown_nice(RB_POWEROFF); } static int diff --git a/sys/sparc64/sparc64/tick.c b/sys/sparc64/sparc64/tick.c index cfd5776..130efa6 100644 --- a/sys/sparc64/sparc64/tick.c +++ b/sys/sparc64/sparc64/tick.c @@ -93,8 +93,8 @@ static timecounter_get_t stick_get_timecount_mp; static timecounter_get_t stick_get_timecount_up; static rd_tick_t stick_rd; static wr_tick_cmpr_t stick_wr_cmpr; -static int tick_et_start(struct eventtimer *et, struct bintime *first, - struct bintime *period); +static int tick_et_start(struct eventtimer *et, sbintime_t first, + sbintime_t period); static int tick_et_stop(struct eventtimer *et); #ifdef SMP static timecounter_get_t tick_get_timecount_mp; @@ -227,10 +227,8 @@ cpu_initclocks(void) ET_FLAGS_PERCPU; tick_et.et_quality = 1000; tick_et.et_frequency = tick_et_use_stick ? sclock : clock; - tick_et.et_min_period.sec = 0; - tick_et.et_min_period.frac = 0x00010000LLU << 32; /* To be safe. */ - tick_et.et_max_period.sec = 3600 * 24; /* No practical limit. */ - tick_et.et_max_period.frac = 0; + tick_et.et_min_period = 0x00010000LLU; /* To be safe. */ + tick_et.et_max_period = (0xfffffffeLLU << 32) / tick_et.et_frequency; tick_et.et_start = tick_et_start; tick_et.et_stop = tick_et_stop; tick_et.et_priv = NULL; @@ -355,23 +353,18 @@ tick_get_timecount_mp(struct timecounter *tc) #endif static int -tick_et_start(struct eventtimer *et, struct bintime *first, - struct bintime *period) +tick_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { u_long base, div, fdiv; register_t s; - if (period != NULL) { - div = (tick_et.et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - div += tick_et.et_frequency * period->sec; - } else + if (period != 0) + div = (tick_et.et_frequency * period) >> 32; + else div = 0; - if (first != NULL) { - fdiv = (tick_et.et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += tick_et.et_frequency * first->sec; - } else + if (first != 0) + fdiv = (tick_et.et_frequency * first) >> 32; + else fdiv = div; PCPU_SET(tickincrement, div); diff --git a/sys/sys/capability.h b/sys/sys/capability.h index a163c4c..27e56c2 100644 --- a/sys/sys/capability.h +++ b/sys/sys/capability.h @@ -1,10 +1,14 @@ /*- * Copyright (c) 2008-2010 Robert N. M. Watson + * Copyright (c) 2012 FreeBSD Foundation * All rights reserved. * * This software was developed at the University of Cambridge Computer * Laboratory with support from a grant from Google, Inc. * + * Portions of this software were developed by Pawel Jakub Dawidek under + * sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,9 +40,10 @@ #define _SYS_CAPABILITY_H_ #include <sys/cdefs.h> -#include <sys/types.h> +#include <sys/param.h> #include <sys/file.h> +#include <sys/fcntl.h> /* * Possible rights on capabilities. @@ -54,34 +59,69 @@ * involve reads or writes depending a great deal on context. */ -/* General file I/O. */ -#define CAP_READ 0x0000000000000001ULL /* read/recv */ -#define CAP_WRITE 0x0000000000000002ULL /* write/send */ -#define CAP_MMAP 0x0000000000000004ULL /* mmap */ -#define CAP_MAPEXEC 0x0000000000000008ULL /* mmap(2) as exec */ +#define CAP_NONE 0x0000000000000000ULL + +/* + * General file I/O. + */ +/* Allows for openat(O_RDONLY), read(2), readv(2). */ +#define CAP_READ 0x0000000000000001ULL +/* Allows for openat(O_WRONLY | O_APPEND), write(2), writev(2). */ +#define CAP_WRITE 0x0000000000000002ULL +/* Allows for lseek(2). */ +#define CAP_SEEK 0x0000000000000080ULL +/* Allows for pread(2), preadv(2). */ +#define CAP_PREAD (CAP_SEEK | CAP_READ) +/* Allows for openat(O_WRONLY) (without O_APPEND), pwrite(2), pwritev(2). */ +#define CAP_PWRITE (CAP_SEEK | CAP_WRITE) +/* Allows for mmap(PROT_NONE). */ +#define CAP_MMAP 0x0000000000000004ULL +/* Allows for mmap(PROT_READ). */ +#define CAP_MMAP_R (CAP_MMAP | CAP_SEEK | CAP_READ) +/* Allows for mmap(PROT_WRITE). */ +#define CAP_MMAP_W (CAP_MMAP | CAP_SEEK | CAP_WRITE) +/* Allows for mmap(PROT_EXEC). */ +#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000008ULL) +/* Allows for mmap(PROT_READ | PROT_WRITE). */ +#define CAP_MMAP_RW (CAP_MMAP_R | CAP_MMAP_W) +/* Allows for mmap(PROT_READ | PROT_EXEC). */ +#define CAP_MMAP_RX (CAP_MMAP_R | CAP_MMAP_X) +/* Allows for mmap(PROT_WRITE | PROT_EXEC). */ +#define CAP_MMAP_WX (CAP_MMAP_W | CAP_MMAP_X) +/* Allows for mmap(PROT_READ | PROT_WRITE | PROT_EXEC). */ +#define CAP_MMAP_RWX (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X) +/* Allows for openat(O_CREAT). */ +#define CAP_CREATE 0x0000000000080000ULL +/* Allows for openat(O_EXEC) and fexecve(2) in turn. */ #define CAP_FEXECVE 0x0000000000000010ULL +/* Allows for openat(O_SYNC), openat(O_FSYNC), fsync(2). */ #define CAP_FSYNC 0x0000000000000020ULL +/* Allows for openat(O_TRUNC), ftruncate(2). */ #define CAP_FTRUNCATE 0x0000000000000040ULL -#define CAP_SEEK 0x0000000000000080ULL /* VFS methods. */ -#define CAP_FCHFLAGS 0x0000000000000100ULL #define CAP_FCHDIR 0x0000000000000200ULL +#define CAP_FCHFLAGS 0x0000000000000100ULL #define CAP_FCHMOD 0x0000000000000400ULL +#define CAP_FCHMODAT CAP_FCHMOD #define CAP_FCHOWN 0x0000000000000800ULL +#define CAP_FCHOWNAT CAP_FCHOWN #define CAP_FCNTL 0x0000000000001000ULL -#define CAP_FPATHCONF 0x0000000000002000ULL #define CAP_FLOCK 0x0000000000004000ULL +#define CAP_FPATHCONF 0x0000000000002000ULL #define CAP_FSCK 0x0000000000008000ULL #define CAP_FSTAT 0x0000000000010000ULL +#define CAP_FSTATAT CAP_FSTAT #define CAP_FSTATFS 0x0000000000020000ULL #define CAP_FUTIMES 0x0000000000040000ULL -#define CAP_CREATE 0x0000000000080000ULL -#define CAP_DELETE 0x0000000000100000ULL -#define CAP_MKDIR 0x0000000000200000ULL -#define CAP_RMDIR 0x0000000000400000ULL -#define CAP_MKFIFO 0x0000000000800000ULL -#define CAP_MKNOD 0x0080000000000000ULL +#define CAP_FUTIMESAT CAP_FUTIMES +#define CAP_LINKAT 0x0000000000400000ULL +#define CAP_MKDIRAT 0x0000000000200000ULL +#define CAP_MKFIFOAT 0x0000000000800000ULL +#define CAP_MKNODAT 0x0080000000000000ULL +#define CAP_RENAMEAT 0x0200000000000000ULL +#define CAP_SYMLINKAT 0x0100000000000000ULL +#define CAP_UNLINKAT 0x0000000000100000ULL /* Lookups - used to constrain *at() calls. */ #define CAP_LOOKUP 0x0000000001000000ULL @@ -107,13 +147,18 @@ #define CAP_GETSOCKOPT 0x0000004000000000ULL #define CAP_LISTEN 0x0000008000000000ULL #define CAP_PEELOFF 0x0000010000000000ULL +#define CAP_RECV CAP_READ +#define CAP_SEND CAP_WRITE #define CAP_SETSOCKOPT 0x0000020000000000ULL #define CAP_SHUTDOWN 0x0000040000000000ULL -#define CAP_SOCK_ALL \ - (CAP_ACCEPT | CAP_BIND | CAP_CONNECT \ - | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT \ - | CAP_LISTEN | CAP_PEELOFF | CAP_SETSOCKOPT | CAP_SHUTDOWN) +#define CAP_SOCK_CLIENT \ + (CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \ + CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN) +#define CAP_SOCK_SERVER \ + (CAP_ACCEPT | CAP_BIND | CAP_GETPEERNAME | CAP_GETSOCKNAME | \ + CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND | \ + CAP_SETSOCKOPT | CAP_SHUTDOWN) /* Mandatory Access Control. */ #define CAP_MAC_GET 0x0000080000000000ULL @@ -138,40 +183,77 @@ #define CAP_PDKILL 0x0040000000000000ULL /* The mask of all valid method rights. */ -#define CAP_MASK_VALID 0x00ffffffffffffffULL +#define CAP_MASK_VALID 0x03ffffffffffffffULL +#define CAP_ALL CAP_MASK_VALID -#ifdef _KERNEL +/* Available bits. */ +#define CAP_UNUSED5 0x0400000000000000ULL +#define CAP_UNUSED4 0x0800000000000000ULL +#define CAP_UNUSED3 0x1000000000000000ULL +#define CAP_UNUSED2 0x2000000000000000ULL +#define CAP_UNUSED1 0x4000000000000000ULL +#define CAP_UNUSED0 0x8000000000000000ULL -#define IN_CAPABILITY_MODE(td) (td->td_ucred->cr_flags & CRED_FLAG_CAPMODE) +/* + * The following defines are provided for backward API compatibility and + * should not be used in new code. + */ +#define CAP_MAPEXEC CAP_MMAP_X +#define CAP_DELETE CAP_UNLINKAT +#define CAP_MKDIR CAP_MKDIRAT +#define CAP_RMDIR CAP_UNLINKAT +#define CAP_MKFIFO CAP_MKFIFOAT +#define CAP_MKNOD CAP_MKNODAT +#define CAP_SOCK_ALL (CAP_SOCK_CLIENT | CAP_SOCK_SERVER) /* - * Create a capability to wrap a file object. + * Allowed fcntl(2) commands. */ -int kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, - int *capfd); +#define CAP_FCNTL_GETFL (1 << F_GETFL) +#define CAP_FCNTL_SETFL (1 << F_SETFL) +#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +#define CAP_FCNTL_GETOWN (1 << F_GETOWN) +#define CAP_FCNTL_SETOWN (1 << F_SETOWN) +#endif +#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +#define CAP_FCNTL_ALL (CAP_FCNTL_GETFL | CAP_FCNTL_SETFL | \ + CAP_FCNTL_GETOWN | CAP_FCNTL_SETOWN) +#else +#define CAP_FCNTL_ALL (CAP_FCNTL_GETFL | CAP_FCNTL_SETFL) +#endif + +#define CAP_IOCTLS_ALL SSIZE_MAX + +#ifdef _KERNEL + +#include <sys/systm.h> + +#define IN_CAPABILITY_MODE(td) ((td->td_ucred->cr_flags & CRED_FLAG_CAPMODE) != 0) + +struct filedesc; /* - * Unwrap a capability if its rights mask is a superset of 'rights'. - * - * Unwrapping a non-capability is effectively a no-op; the value of fp_cap - * is simply copied into fpp. + * Test whether a capability grants the requested rights. + */ +int cap_check(cap_rights_t have, cap_rights_t need); +/* + * Convert capability rights into VM access flags. */ -int cap_funwrap(struct file *fp_cap, cap_rights_t rights, - struct file **fpp); -int cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, - u_char *maxprotp, struct file **fpp); +u_char cap_rights_to_vmprot(cap_rights_t have); /* * For the purposes of procstat(1) and similar tools, allow kern_descrip.c to - * extract the rights from a capability. However, this should not be used by - * kernel code generally, instead cap_funwrap() should be used in order to - * keep all access control in one place. + * extract the rights from a capability. */ -cap_rights_t cap_rights(struct file *fp_cap); +cap_rights_t cap_rights(struct filedesc *fdp, int fd); + +int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd); +int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd); #else /* !_KERNEL */ __BEGIN_DECLS +#include <stdbool.h> /* * cap_enter(): Cause the process to enter capability mode, which will @@ -187,21 +269,46 @@ __BEGIN_DECLS int cap_enter(void); /* - * cap_getmode(): Are we in capability mode? + * Are we sandboxed (in capability mode)? + * This is a libc wrapper around the cap_getmode(2) system call. */ -int cap_getmode(u_int* modep); +bool cap_sandboxed(void); /* - * cap_new(): Create a new capability derived from an existing file - * descriptor with the specified rights. If the existing file descriptor is - * a capability, then the new rights must be a subset of the existing rights. + * cap_getmode(): Are we in capability mode? */ -int cap_new(int fd, cap_rights_t rights); +int cap_getmode(u_int *modep); /* - * cap_getrights(): Query the rights on a capability. + * Limits capability rights for the given descriptor (CAP_*). + */ +int cap_rights_limit(int fd, cap_rights_t rights); +/* + * Returns bitmask of capability rights for the given descriptor. */ -int cap_getrights(int fd, cap_rights_t *rightsp); +int cap_rights_get(int fd, cap_rights_t *rightsp); +/* + * Limits allowed ioctls for the given descriptor. + */ +int cap_ioctls_limit(int fd, const unsigned long *cmds, size_t ncmds); +/* + * Returns array of allowed ioctls for the given descriptor. + * If all ioctls are allowed, the cmds array is not populated and + * the function returns CAP_IOCTLS_ALL. + */ +ssize_t cap_ioctls_get(int fd, unsigned long *cmds, size_t maxcmds); +/* + * Limits allowed fcntls for the given descriptor (CAP_FCNTL_*). + */ +int cap_fcntls_limit(int fd, uint32_t fcntlrights); +/* + * Returns bitmask of allowed fcntls for the given descriptor. + */ +int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); + +/* For backward compatibility. */ +int cap_new(int fd, cap_rights_t rights); +#define cap_getrights(fd, rightsp) cap_rights_get((fd), (rightsp)) __END_DECLS diff --git a/sys/sys/file.h b/sys/sys/file.h index cf5f1ea..cfdc1d8 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -64,12 +64,12 @@ struct socket; #define DTYPE_SEM 9 /* posix semaphore */ #define DTYPE_PTS 10 /* pseudo teletype master device */ #define DTYPE_DEV 11 /* Device specific fd type */ -#define DTYPE_CAPABILITY 12 /* capability */ -#define DTYPE_PROCDESC 13 /* process descriptor */ +#define DTYPE_PROCDESC 12 /* process descriptor */ #ifdef _KERNEL struct file; +struct filecaps; struct ucred; #define FOF_OFFSET 0x01 /* Use the offset in uio argument */ @@ -217,7 +217,6 @@ int fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp); int fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp); -int fgetcap(struct thread *td, int fd, struct file **fpp); int _fdrop(struct file *fp, struct thread *td); /* @@ -242,7 +241,7 @@ int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); int fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, - cap_rights_t *have, struct vnode **vpp); + struct filecaps *havecaps, struct vnode **vpp); int fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); int fgetvp_write(struct thread *td, int fd, cap_rights_t rights, diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 07cfb1f..f3e3a09 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -41,6 +41,23 @@ #include <machine/_limits.h> +struct filecaps { + cap_rights_t fc_rights; /* per-descriptor capability rights */ + uint32_t fc_fcntls; /* per-descriptor allowed fcntls */ + u_long *fc_ioctls; /* per-descriptor allowed ioctls */ + int16_t fc_nioctls; /* fc_ioctls array size */ +}; + +struct filedescent { + struct file *fde_file; /* file structure for open file */ + struct filecaps fde_caps; /* per-descriptor rights */ + uint8_t fde_flags; /* per-process open file flags */ +}; +#define fde_rights fde_caps.fc_rights +#define fde_fcntls fde_caps.fc_fcntls +#define fde_ioctls fde_caps.fc_ioctls +#define fde_nioctls fde_caps.fc_nioctls + /* * This structure is used for the management of descriptors. It may be * shared by multiple processes. @@ -48,8 +65,7 @@ #define NDSLOTTYPE u_long struct filedesc { - struct file **fd_ofiles; /* file structures for open files */ - char *fd_ofileflags; /* per-process open file flags */ + struct filedescent *fd_ofiles; /* open files */ struct vnode *fd_cdir; /* current directory */ struct vnode *fd_rdir; /* root directory */ struct vnode *fd_jdir; /* jail root directory */ @@ -92,6 +108,15 @@ struct filedesc_to_leader { #ifdef _KERNEL +#include <sys/systm.h> /* CTASSERT() */ + +CTASSERT(sizeof(cap_rights_t) == sizeof(uint64_t)); + +/* Flags for do_dup() */ +#define DUP_FIXED 0x1 /* Force fixed allocation. */ +#define DUP_FCNTL 0x2 /* fcntl()-style errors. */ +#define DUP_CLOEXEC 0x4 /* Atomically set FD_CLOEXEC. */ + /* Lock a file descriptor table. */ #define FILEDESC_LOCK_INIT(fdp) sx_init(&(fdp)->fd_sx, "filedesc structure") #define FILEDESC_LOCK_DESTROY(fdp) sx_destroy(&(fdp)->fd_sx) @@ -109,13 +134,20 @@ struct filedesc_to_leader { struct thread; +void filecaps_init(struct filecaps *fcaps); +void filecaps_copy(const struct filecaps *src, struct filecaps *dst); +void filecaps_free(struct filecaps *fcaps); + int closef(struct file *fp, struct thread *td); +int do_dup(struct thread *td, int flags, int old, int new, + register_t *retval); int dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, int openerror, int *indxp); int falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags); int falloc_noinstall(struct thread *td, struct file **resultfp); -int finstall(struct thread *td, struct file *fp, int *resultfp, int flags); +int finstall(struct thread *td, struct file *fp, int *resultfp, int flags, + struct filecaps *fcaps); int fdalloc(struct thread *td, int minfd, int *result); int fdavail(struct thread *td, int n); int fdcheckstd(struct thread *td); @@ -123,7 +155,7 @@ void fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td); void fdcloseexec(struct thread *td); struct filedesc *fdcopy(struct filedesc *fdp); void fdunshare(struct proc *p, struct thread *td); -void fdfree(struct thread *td); +void fdescfree(struct thread *td); struct filedesc *fdinit(struct filedesc *fdp); struct filedesc *fdshare(struct filedesc *fdp); struct filedesc_to_leader * @@ -135,7 +167,8 @@ void mountcheckdirs(struct vnode *olddp, struct vnode *newdp); void setugidsafety(struct thread *td); /* Return a referenced file from an unlocked descriptor. */ -struct file *fget_unlocked(struct filedesc *fdp, int fd); +int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights, + int needfcntl, struct file **fpp, cap_rights_t *haverightsp); /* Requires a FILEDESC_{S,X}LOCK held and returns without a ref. */ static __inline struct file * @@ -147,7 +180,7 @@ fget_locked(struct filedesc *fdp, int fd) if (fd < 0 || fd >= fdp->fd_nfiles) return (NULL); - return (fdp->fd_ofiles[fd]); + return (fdp->fd_ofiles[fd].fde_file); } #endif /* _KERNEL */ diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 3b43916..a9992f4 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -33,6 +33,7 @@ #ifndef _SYS_NAMEI_H_ #define _SYS_NAMEI_H_ +#include <sys/filedesc.h> #include <sys/queue.h> #include <sys/uio.h> @@ -75,7 +76,7 @@ struct nameidata { /* * Results: returned from namei */ - cap_rights_t ni_baserights; /* rights the *at base has (or -1) */ + struct filecaps ni_filecaps; /* rights the *at base has */ /* * Results: returned from/manipulated by lookup */ @@ -180,7 +181,7 @@ NDINIT_ALL(struct nameidata *ndp, ndp->ni_startdir = startdir; ndp->ni_strictrelative = 0; ndp->ni_rightsneeded = rights; - ndp->ni_baserights = 0; + filecaps_init(&ndp->ni_filecaps); ndp->ni_cnd.cn_thread = td; } diff --git a/sys/sys/proc.h b/sys/sys/proc.h index ade2864..f6cf2e4 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -273,6 +273,7 @@ struct thread { struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ pid_t td_dbg_forked; /* (c) Child pid for debugger. */ u_int td_vp_reserv; /* (k) Count of reserved vnodes. */ + int td_no_sleeping; /* (k) Sleeping disabled count. */ #define td_endzero td_sigmask /* Copied during fork1() or create_thread(). */ @@ -404,7 +405,7 @@ do { \ #define TDP_ALTSTACK 0x00000020 /* Have alternate signal stack. */ #define TDP_DEADLKTREAT 0x00000040 /* Lock aquisition - deadlock treatment. */ #define TDP_NOFAULTING 0x00000080 /* Do not handle page faults. */ -#define TDP_NOSLEEPING 0x00000100 /* Thread is not allowed to sleep on a sq. */ +#define TDP_UNUSED9 0x00000100 /* --available-- */ #define TDP_OWEUPC 0x00000200 /* Call addupc() at next AST. */ #define TDP_ITHREAD 0x00000400 /* Thread is an interrupt thread. */ #define TDP_SYNCIO 0x00000800 /* Local override, disable async i/o. */ @@ -790,17 +791,9 @@ extern pid_t pid_max; #define thread_safetoswapout(td) ((td)->td_flags & TDF_CANSWAP) /* Control whether or not it is safe for curthread to sleep. */ -#define THREAD_NO_SLEEPING() do { \ - KASSERT(!(curthread->td_pflags & TDP_NOSLEEPING), \ - ("nested no sleeping")); \ - curthread->td_pflags |= TDP_NOSLEEPING; \ -} while (0) +#define THREAD_NO_SLEEPING() ((curthread)->td_no_sleeping++) -#define THREAD_SLEEPING_OK() do { \ - KASSERT((curthread->td_pflags & TDP_NOSLEEPING), \ - ("nested sleeping ok")); \ - curthread->td_pflags &= ~TDP_NOSLEEPING; \ -} while (0) +#define THREAD_SLEEPING_OK() ((curthread)->td_no_sleeping--) #define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash]) extern LIST_HEAD(pidhashhead, proc) *pidhashtbl; @@ -908,7 +901,7 @@ void tidhash_add(struct thread *); void tidhash_remove(struct thread *); void cpu_idle(int); int cpu_idle_wakeup(int); -extern void (*cpu_idle_hook)(void); /* Hook to machdep CPU idler. */ +extern void (*cpu_idle_hook)(sbintime_t); /* Hook to machdep CPU idler. */ void cpu_switch(struct thread *, struct thread *, struct mtx *); void cpu_throw(struct thread *, struct thread *) __dead2; void unsleep(struct thread *); diff --git a/sys/sys/rmlock.h b/sys/sys/rmlock.h index 0ae2099..5a0fa8a 100644 --- a/sys/sys/rmlock.h +++ b/sys/sys/rmlock.h @@ -40,7 +40,7 @@ #ifdef _KERNEL /* - * Flags passed to rm_init(9). + * Flags passed to rm_init_flags(9). */ #define RM_NOWITNESS 0x00000001 #define RM_RECURSE 0x00000002 diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 6b0cd67..5a2a1f6 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #define SYS_syscall 0 @@ -435,7 +435,7 @@ #define SYS_shmctl 512 #define SYS_lpathconf 513 #define SYS_cap_new 514 -#define SYS_cap_getrights 515 +#define SYS_cap_rights_get 515 #define SYS_cap_enter 516 #define SYS_cap_getmode 517 #define SYS_pdfork 518 @@ -452,4 +452,9 @@ #define SYS_posix_fallocate 530 #define SYS_posix_fadvise 531 #define SYS_wait6 532 -#define SYS_MAXSYSCALL 533 +#define SYS_cap_rights_limit 533 +#define SYS_cap_ioctls_limit 534 +#define SYS_cap_ioctls_get 535 +#define SYS_cap_fcntls_limit 536 +#define SYS_cap_fcntls_get 537 +#define SYS_MAXSYSCALL 538 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 25f0470..3e2a3d4 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: head/sys/kern/syscalls.master 242958 2012-11-13 12:52:31Z kib +# created from FreeBSD: head/sys/kern/syscalls.master 247602 2013-03-02 00:53:12Z pjd MIASM = \ syscall.o \ exit.o \ @@ -384,7 +384,7 @@ MIASM = \ shmctl.o \ lpathconf.o \ cap_new.o \ - cap_getrights.o \ + cap_rights_get.o \ cap_enter.o \ cap_getmode.o \ pdfork.o \ @@ -400,4 +400,9 @@ MIASM = \ rctl_remove_rule.o \ posix_fallocate.o \ posix_fadvise.o \ - wait6.o + wait6.o \ + cap_rights_limit.o \ + cap_ioctls_limit.o \ + cap_ioctls_get.o \ + cap_fcntls_limit.o \ + cap_fcntls_get.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index ef59ad5..8ef4080 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 242958 2012-11-13 12:52:31Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 247602 2013-03-02 00:53:12Z pjd */ #ifndef _SYS_SYSPROTO_H_ @@ -1676,7 +1676,7 @@ struct cap_new_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char rights_l_[PADL_(uint64_t)]; uint64_t rights; char rights_r_[PADR_(uint64_t)]; }; -struct cap_getrights_args { +struct cap_rights_get_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char rightsp_l_[PADL_(uint64_t *)]; uint64_t * rightsp; char rightsp_r_[PADR_(uint64_t *)]; }; @@ -1762,6 +1762,28 @@ struct wait6_args { char wrusage_l_[PADL_(struct __wrusage *)]; struct __wrusage * wrusage; char wrusage_r_[PADR_(struct __wrusage *)]; char info_l_[PADL_(siginfo_t *)]; siginfo_t * info; char info_r_[PADR_(siginfo_t *)]; }; +struct cap_rights_limit_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char rights_l_[PADL_(uint64_t)]; uint64_t rights; char rights_r_[PADR_(uint64_t)]; +}; +struct cap_ioctls_limit_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char cmds_l_[PADL_(const u_long *)]; const u_long * cmds; char cmds_r_[PADR_(const u_long *)]; + char ncmds_l_[PADL_(size_t)]; size_t ncmds; char ncmds_r_[PADR_(size_t)]; +}; +struct cap_ioctls_get_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char cmds_l_[PADL_(u_long *)]; u_long * cmds; char cmds_r_[PADR_(u_long *)]; + char maxcmds_l_[PADL_(size_t)]; size_t maxcmds; char maxcmds_r_[PADR_(size_t)]; +}; +struct cap_fcntls_limit_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char fcntlrights_l_[PADL_(uint32_t)]; uint32_t fcntlrights; char fcntlrights_r_[PADR_(uint32_t)]; +}; +struct cap_fcntls_get_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char fcntlrightsp_l_[PADL_(uint32_t *)]; uint32_t * fcntlrightsp; char fcntlrightsp_r_[PADR_(uint32_t *)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_sys_exit(struct thread *, struct sys_exit_args *); int sys_fork(struct thread *, struct fork_args *); @@ -2127,7 +2149,7 @@ int sys_msgctl(struct thread *, struct msgctl_args *); int sys_shmctl(struct thread *, struct shmctl_args *); int sys_lpathconf(struct thread *, struct lpathconf_args *); int sys_cap_new(struct thread *, struct cap_new_args *); -int sys_cap_getrights(struct thread *, struct cap_getrights_args *); +int sys_cap_rights_get(struct thread *, struct cap_rights_get_args *); int sys_cap_enter(struct thread *, struct cap_enter_args *); int sys_cap_getmode(struct thread *, struct cap_getmode_args *); int sys_pdfork(struct thread *, struct pdfork_args *); @@ -2144,6 +2166,11 @@ int sys_rctl_remove_rule(struct thread *, struct rctl_remove_rule_args *); int sys_posix_fallocate(struct thread *, struct posix_fallocate_args *); int sys_posix_fadvise(struct thread *, struct posix_fadvise_args *); int sys_wait6(struct thread *, struct wait6_args *); +int sys_cap_rights_limit(struct thread *, struct cap_rights_limit_args *); +int sys_cap_ioctls_limit(struct thread *, struct cap_ioctls_limit_args *); +int sys_cap_ioctls_get(struct thread *, struct cap_ioctls_get_args *); +int sys_cap_fcntls_limit(struct thread *, struct cap_fcntls_limit_args *); +int sys_cap_fcntls_get(struct thread *, struct cap_fcntls_get_args *); #ifdef COMPAT_43 @@ -2823,7 +2850,7 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_shmctl AUE_SHMCTL #define SYS_AUE_lpathconf AUE_LPATHCONF #define SYS_AUE_cap_new AUE_CAP_NEW -#define SYS_AUE_cap_getrights AUE_CAP_GETRIGHTS +#define SYS_AUE_cap_rights_get AUE_CAP_RIGHTS_GET #define SYS_AUE_cap_enter AUE_CAP_ENTER #define SYS_AUE_cap_getmode AUE_CAP_GETMODE #define SYS_AUE_pdfork AUE_PDFORK @@ -2840,6 +2867,11 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_posix_fallocate AUE_NULL #define SYS_AUE_posix_fadvise AUE_NULL #define SYS_AUE_wait6 AUE_WAIT6 +#define SYS_AUE_cap_rights_limit AUE_CAP_RIGHTS_LIMIT +#define SYS_AUE_cap_ioctls_limit AUE_CAP_IOCTLS_LIMIT +#define SYS_AUE_cap_ioctls_get AUE_CAP_IOCTLS_GET +#define SYS_AUE_cap_fcntls_limit AUE_CAP_FCNTLS_LIMIT +#define SYS_AUE_cap_fcntls_get AUE_CAP_FCNTLS_GET #undef PAD_ #undef PADL_ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 611d014..2bf8056 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -44,6 +44,7 @@ #include <sys/cdefs.h> #include <sys/queue.h> #include <sys/stdint.h> /* for people using printf mainly */ +#include <sys/time.h> extern int cold; /* nonzero if we are doing a cold boot */ extern int rebooting; /* kern_reboot() has been called. */ @@ -267,7 +268,7 @@ void startprofclock(struct proc *); void stopprofclock(struct proc *); void cpu_startprofclock(void); void cpu_stopprofclock(void); -void cpu_idleclock(void); +sbintime_t cpu_idleclock(void); void cpu_activeclock(void); extern int cpu_can_deep_sleep; extern int cpu_disable_deep_sleep; diff --git a/sys/sys/time.h b/sys/sys/time.h index 80878c0..555c37e 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -109,6 +109,36 @@ bintime_mul(struct bintime *bt, u_int x) ((a)->frac cmp (b)->frac) : \ ((a)->sec cmp (b)->sec)) +#define SBT_1S ((sbintime_t)1 << 32) +#define SBT_1M (SBT_1S * 60) +#define SBT_1MS (SBT_1S / 1000) +#define SBT_1US (SBT_1S / 1000000) +#define SBT_1NS (SBT_1S / 1000000000) + +static __inline int +sbintime_getsec(sbintime_t sbt) +{ + + return (sbt >> 32); +} + +static __inline sbintime_t +bttosbt(const struct bintime bt) +{ + + return (((sbintime_t)bt.sec << 32) + (bt.frac >> 32)); +} + +static __inline struct bintime +sbttobt(sbintime_t sbt) +{ + struct bintime bt; + + bt.sec = sbt >> 32; + bt.frac = sbt << 32; + return (bt); +} + /*- * Background information: * @@ -156,6 +186,42 @@ timeval2bintime(const struct timeval *tv, struct bintime *bt) /* 18446744073709 = int(2^64 / 1000000) */ bt->frac = tv->tv_usec * (uint64_t)18446744073709LL; } + +static __inline struct timespec +sbttots(sbintime_t sbt) +{ + struct timespec ts; + + ts.tv_sec = sbt >> 32; + ts.tv_nsec = ((uint64_t)1000000000 * (uint32_t)sbt) >> 32; + return (ts); +} + +static __inline sbintime_t +tstosbt(struct timespec ts) +{ + + return (((sbintime_t)ts.tv_sec << 32) + + (ts.tv_nsec * (((uint64_t)1 << 63) / 500000000) >> 32)); +} + +static __inline struct timeval +sbttotv(sbintime_t sbt) +{ + struct timeval tv; + + tv.tv_sec = sbt >> 32; + tv.tv_usec = ((uint64_t)1000000 * (uint32_t)sbt) >> 32; + return (tv); +} + +static __inline sbintime_t +tvtosbt(struct timeval tv) +{ + + return (((sbintime_t)tv.tv_sec << 32) + + (tv.tv_usec * (((uint64_t)1 << 63) / 500000) >> 32)); +} #endif /* __BSD_VISIBLE */ #ifdef _KERNEL @@ -317,6 +383,15 @@ void binuptime(struct bintime *bt); void nanouptime(struct timespec *tsp); void microuptime(struct timeval *tvp); +static __inline sbintime_t +sbinuptime(void) +{ + struct bintime bt; + + binuptime(&bt); + return (bttosbt(bt)); +} + void bintime(struct bintime *bt); void nanotime(struct timespec *tsp); void microtime(struct timeval *tvp); @@ -325,6 +400,15 @@ void getbinuptime(struct bintime *bt); void getnanouptime(struct timespec *tsp); void getmicrouptime(struct timeval *tvp); +static __inline sbintime_t +getsbinuptime(void) +{ + struct bintime bt; + + getbinuptime(&bt); + return (bttosbt(bt)); +} + void getbintime(struct bintime *bt); void getnanotime(struct timespec *tsp); void getmicrotime(struct timeval *tvp); diff --git a/sys/sys/timeet.h b/sys/sys/timeet.h index 87392a2..23a170c 100644 --- a/sys/sys/timeet.h +++ b/sys/sys/timeet.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> + * Copyright (c) 2010-2013 Alexander Motin <mav@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,7 @@ struct eventtimer; typedef int et_start_t(struct eventtimer *et, - struct bintime *first, struct bintime *period); + sbintime_t first, sbintime_t period); typedef int et_stop_t(struct eventtimer *et); typedef void et_event_cb_t(struct eventtimer *et, void *arg); typedef int et_deregister_cb_t(struct eventtimer *et, void *arg); @@ -70,8 +70,8 @@ struct eventtimer { int et_active; u_int64_t et_frequency; /* Base frequency in Hz. */ - struct bintime et_min_period; - struct bintime et_max_period; + sbintime_t et_min_period; + sbintime_t et_max_period; et_start_t *et_start; et_stop_t *et_stop; et_event_cb_t *et_event_cb; @@ -93,8 +93,7 @@ int et_deregister(struct eventtimer *et); struct eventtimer *et_find(const char *name, int check, int want); int et_init(struct eventtimer *et, et_event_cb_t *event, et_deregister_cb_t *deregister, void *arg); -int et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period); +int et_start(struct eventtimer *et, sbintime_t first, sbintime_t period); int et_stop(struct eventtimer *et); int et_ban(struct eventtimer *et); int et_free(struct eventtimer *et); diff --git a/sys/sys/types.h b/sys/sys/types.h index 491e99d..cc0bca8 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -188,6 +188,8 @@ typedef __rlim_t rlim_t; /* resource limit */ #define _RLIM_T_DECLARED #endif +typedef __int64_t sbintime_t; + typedef __segsz_t segsz_t; /* segment size (in pages) */ #ifndef _SIZE_T_DECLARED diff --git a/sys/sys/user.h b/sys/sys/user.h index ddaccb8..5de76ac 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -251,8 +251,7 @@ struct user { #define KF_TYPE_SHM 8 #define KF_TYPE_SEM 9 #define KF_TYPE_PTS 10 -/* no KF_TYPE_CAPABILITY (11), since capabilities wrap other file objects */ -#define KF_TYPE_PROCDESC 12 +#define KF_TYPE_PROCDESC 11 #define KF_TYPE_UNKNOWN 255 #define KF_VTYPE_VNON 0 @@ -288,7 +287,6 @@ struct user { #define KF_FLAG_TRUNC 0x00001000 #define KF_FLAG_EXCL 0x00002000 #define KF_FLAG_EXEC 0x00004000 -#define KF_FLAG_CAPABILITY 0x00008000 /* * Old format. Has variable hidden padding due to alignment. diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 85b4df2..248d9e8 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -306,13 +306,13 @@ sys_mmap(td, uap) */ rights = CAP_MMAP; if (prot & PROT_READ) - rights |= CAP_READ; + rights |= CAP_MMAP_R; if ((flags & MAP_SHARED) != 0) { if (prot & PROT_WRITE) - rights |= CAP_WRITE; + rights |= CAP_MMAP_W; } if (prot & PROT_EXEC) - rights |= CAP_MAPEXEC; + rights |= CAP_MMAP_X; if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot, &fp)) != 0) goto done; diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c index c6a6f8c..69c2157 100644 --- a/sys/x86/isa/atrtc.c +++ b/sys/x86/isa/atrtc.c @@ -164,11 +164,10 @@ struct atrtc_softc { }; static int -rtc_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { - atrtc_rate(max(fls((period->frac + (period->frac >> 1)) >> 32) - 17, 1)); + atrtc_rate(max(fls(period + (period >> 1)) - 17, 1)); atrtc_enable_intr(); return (0); } @@ -277,10 +276,8 @@ atrtc_attach(device_t dev) sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV; sc->et.et_quality = 0; sc->et.et_frequency = 32768; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = 0x0008LLU << 48; - sc->et.et_max_period.sec = 0; - sc->et.et_max_period.frac = 0x8000LLU << 48; + sc->et.et_min_period = 0x00080000; + sc->et.et_max_period = 0x80000000; sc->et.et_start = rtc_start; sc->et.et_stop = rtc_stop; sc->et.et_priv = dev; diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index 232c913..29ec02d 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -589,18 +589,17 @@ i8254_get_timecount(struct timecounter *tc) } static int -attimer_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +attimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { device_t dev = (device_t)et->et_priv; struct attimer_softc *sc = device_get_softc(dev); - if (period != NULL) { + if (period != 0) { sc->mode = MODE_PERIODIC; - sc->period = period->frac >> 32; + sc->period = period; } else { sc->mode = MODE_ONESHOT; - sc->period = first->frac >> 32; + sc->period = first; } if (!sc->intr_en) { i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc); @@ -755,12 +754,8 @@ attimer_attach(device_t dev) sc->et.et_flags |= ET_FLAGS_ONESHOT; sc->et.et_quality = 100; sc->et.et_frequency = i8254_freq; - sc->et.et_min_period.sec = 0; - sc->et.et_min_period.frac = - ((0x0002LLU << 48) / i8254_freq) << 16; - sc->et.et_max_period.sec = 0xffff / i8254_freq; - sc->et.et_max_period.frac = - ((0xfffeLLU << 48) / i8254_freq) << 16; + sc->et.et_min_period = (0x0002LLU << 32) / i8254_freq; + sc->et.et_max_period = (0xfffeLLU << 32) / i8254_freq; sc->et.et_start = attimer_start; sc->et.et_stop = attimer_stop; sc->et.et_priv = dev; diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index c60db22..ac87ebd 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -169,7 +169,7 @@ static void lapic_timer_stop(struct lapic *); static void lapic_timer_set_divisor(u_int divisor); static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); static int lapic_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period); + sbintime_t first, sbintime_t period); static int lapic_et_stop(struct eventtimer *et); struct pic lapic_pic = { .pic_resume = lapic_resume }; @@ -268,10 +268,8 @@ lapic_init(vm_paddr_t addr) } lapic_et.et_frequency = 0; /* We don't know frequency yet, so trying to guess. */ - lapic_et.et_min_period.sec = 0; - lapic_et.et_min_period.frac = 0x00001000LL << 32; - lapic_et.et_max_period.sec = 1; - lapic_et.et_max_period.frac = 0; + lapic_et.et_min_period = 0x00001000LL; + lapic_et.et_max_period = SBT_1S; lapic_et.et_start = lapic_et_start; lapic_et.et_stop = lapic_et_stop; lapic_et.et_priv = NULL; @@ -487,8 +485,7 @@ lapic_disable_pmc(void) } static int -lapic_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct lapic *la; u_long value; @@ -513,28 +510,18 @@ lapic_et_start(struct eventtimer *et, printf("lapic: Divisor %lu, Frequency %lu Hz\n", lapic_timer_divisor, value); et->et_frequency = value; - et->et_min_period.sec = 0; - et->et_min_period.frac = - ((0x00000002LLU << 32) / et->et_frequency) << 32; - et->et_max_period.sec = 0xfffffffeLLU / et->et_frequency; - et->et_max_period.frac = - ((0xfffffffeLLU << 32) / et->et_frequency) << 32; + et->et_min_period = (0x00000002LLU << 32) / et->et_frequency; + et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency; } if (la->la_timer_mode == 0) lapic_timer_set_divisor(lapic_timer_divisor); - if (period != NULL) { + if (period != 0) { la->la_timer_mode = 1; - la->la_timer_period = - (et->et_frequency * (period->frac >> 32)) >> 32; - if (period->sec != 0) - la->la_timer_period += et->et_frequency * period->sec; + la->la_timer_period = ((uint32_t)et->et_frequency * period) >> 32; lapic_timer_periodic(la, la->la_timer_period, 1); } else { la->la_timer_mode = 2; - la->la_timer_period = - (et->et_frequency * (first->frac >> 32)) >> 32; - if (first->sec != 0) - la->la_timer_period += et->et_frequency * first->sec; + la->la_timer_period = ((uint32_t)et->et_frequency * first) >> 32; lapic_timer_oneshot(la, la->la_timer_period, 1); } return (0); |