From f0cdc18176f3551cc90f4901b73e4c0eb2c3faeb Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Thu, 2 Jun 2011 14:08:50 +0000 Subject: [PATCH 01/31] Empty the network configuration only after the user decided to pick an interface. Otherwise an accidental start of the netowrk configuration and immediate cancel after the install has finished removes the previously configured settings. Discussed with: nwhitehorn Sponsored by: The FreeBSD Foundation Sponsored by: iXsystems --- usr.sbin/bsdinstall/scripts/netconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig index bef57598bb2..d8984e27f79 100755 --- a/usr.sbin/bsdinstall/scripts/netconfig +++ b/usr.sbin/bsdinstall/scripts/netconfig @@ -41,8 +41,6 @@ DIALOG_TAGS="" : ${DIALOG_ITEM_HELP=4} : ${DIALOG_ESC=255} -echo -n > $BSDINSTALL_TMPETC/rc.conf.net - for IF in `ifconfig -l`; do test "$IF" = "lo0" && continue (ifconfig -g wlan | egrep -wq $IF) && continue @@ -56,6 +54,8 @@ INTERFACE=`echo $DIALOG_TAGS | xargs dialog --backtitle 'FreeBSD Installer' --ti if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi exec 3>&- +: > $BSDINSTALL_TMPETC/rc.conf.net + # Do a dirty check to see if this a wireless interface -- there should be a # better way IFCONFIG_PREFIX="" From 1787909001814412439f328012aaf431423e7839 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:12:37 +0000 Subject: [PATCH 02/31] MFpseries: Renovate and improve the AIM Open Firmware support: - Add RTAS (Run-Time Abstraction Services) support, found on all IBM systems and some Apple ones - Improve support for 32-bit real mode Open Firmware systems - Pull some more OF bits over from the AIM directory - Fix memory detection on IBM LPARs and systems with more than one /memory node (by andreast@) --- sys/powerpc/aim/locore32.S | 13 -- sys/powerpc/aim/locore64.S | 132 ------------- sys/powerpc/include/rtas.h | 61 ++++++ sys/powerpc/ofw/ofw_machdep.c | 185 ++++++++++++++---- sys/powerpc/ofw/ofw_real.c | 7 +- sys/powerpc/ofw/ofwcall32.S | 154 +++++++++++++++ sys/powerpc/ofw/ofwcall64.S | 290 ++++++++++++++++++++++++++++ sys/powerpc/{aim => ofw}/ofwmagic.S | 0 sys/powerpc/ofw/rtas.c | 243 +++++++++++++++++++++++ 9 files changed, 898 insertions(+), 187 deletions(-) create mode 100644 sys/powerpc/include/rtas.h create mode 100644 sys/powerpc/ofw/ofwcall32.S create mode 100644 sys/powerpc/ofw/ofwcall64.S rename sys/powerpc/{aim => ofw}/ofwmagic.S (100%) create mode 100644 sys/powerpc/ofw/rtas.c diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S index 64bf81e0411..35ea99bc69c 100644 --- a/sys/powerpc/aim/locore32.S +++ b/sys/powerpc/aim/locore32.S @@ -87,9 +87,6 @@ GLOBAL(tmpstk) GLOBAL(esym) .long 0 /* end of symbol table */ -GLOBAL(ofmsr) - .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ - #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 @@ -99,16 +96,6 @@ GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(eintrcnt) -/* - * File-scope for locore.S - */ -idle_u: - .long 0 /* fake uarea during idle after exit */ -openfirmware_entry: - .long 0 /* Open Firmware entry point */ -srsave: - .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - .text .globl btext btext: diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index acdc8a1e782..e71594e0c67 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -76,7 +76,6 @@ .set kernbase, KERNBASE #define TMPSTKSZ 8192 /* 8K temporary stack */ -#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ /* * Globals @@ -85,14 +84,9 @@ .align 4 GLOBAL(tmpstk) .space TMPSTKSZ -GLOBAL(ofwstk) - .space OFWSTKSZ GLOBAL(esym) .llong 0 /* end of symbol table */ -GLOBAL(ofmsr) - .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ - #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 @@ -102,16 +96,6 @@ GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(eintrcnt) -/* - * File-scope for locore.S - */ -idle_u: - .llong 0 /* fake uarea during idle after exit */ -openfirmware_entry: - .llong 0 /* Open Firmware entry point */ -srsave: - .llong 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - .text .globl btext btext: @@ -207,122 +191,6 @@ ASENTRY(__start) tocbase: .llong .TOC.@tocbase -/* - * Open Firmware Real-mode Entry Point. This is a huge pain. - */ - -ASENTRY(ofw_32bit_mode_entry) - mflr %r0 - std %r0,16(%r1) - stdu %r1,-208(%r1) - - /* - * We need to save the following, because OF's register save/ - * restore code assumes that the contents of registers are - * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These - * get placed in that order in the stack. - */ - - mfcr %r4 - std %r4,48(%r1) - std %r13,56(%r1) - std %r14,64(%r1) - std %r15,72(%r1) - std %r16,80(%r1) - std %r17,88(%r1) - std %r18,96(%r1) - std %r19,104(%r1) - std %r20,112(%r1) - std %r21,120(%r1) - std %r22,128(%r1) - std %r23,136(%r1) - std %r24,144(%r1) - std %r25,152(%r1) - std %r26,160(%r1) - std %r27,168(%r1) - std %r28,176(%r1) - std %r29,184(%r1) - std %r30,192(%r1) - std %r31,200(%r1) - - /* Record the old MSR */ - mfmsr %r6 - - /* read client interface handler */ - lis %r4,openfirmware_entry@ha - ld %r4,openfirmware_entry@l(%r4) - - /* - * Set the MSR to the OF value. This has the side effect of disabling - * exceptions, which is important for the next few steps. - */ - - lis %r5,ofmsr@ha - ld %r5,ofmsr@l(%r5) - mtmsrd %r5 - isync - - /* - * Set up OF stack. This needs to be accessible in real mode and - * use the 32-bit ABI stack frame format. The pointer to the current - * kernel stack is placed at the very top of the stack along with - * the old MSR so we can get them back later. - */ - mr %r5,%r1 - lis %r1,(ofwstk+OFWSTKSZ-32)@ha - addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l - std %r5,8(%r1) /* Save real stack pointer */ - std %r2,16(%r1) /* Save old TOC */ - std %r6,24(%r1) /* Save old MSR */ - li %r5,0 - stw %r5,4(%r1) - stw %r5,0(%r1) - - /* Finally, branch to OF */ - mtctr %r4 - bctrl - - /* Reload stack pointer and MSR from the OFW stack */ - ld %r6,24(%r1) - ld %r2,16(%r1) - ld %r1,8(%r1) - - /* Now set the real MSR */ - mtmsrd %r6 - isync - - /* Sign-extend the return value from OF */ - extsw %r3,%r3 - - /* Restore all the non-volatile registers */ - ld %r5,48(%r1) - mtcr %r5 - ld %r13,56(%r1) - ld %r14,64(%r1) - ld %r15,72(%r1) - ld %r16,80(%r1) - ld %r17,88(%r1) - ld %r18,96(%r1) - ld %r19,104(%r1) - ld %r20,112(%r1) - ld %r21,120(%r1) - ld %r22,128(%r1) - ld %r23,136(%r1) - ld %r24,144(%r1) - ld %r25,152(%r1) - ld %r26,160(%r1) - ld %r27,168(%r1) - ld %r28,176(%r1) - ld %r29,184(%r1) - ld %r30,192(%r1) - ld %r31,200(%r1) - - /* Restore the stack and link register */ - ld %r1,0(%r1) - ld %r0,16(%r1) - mtlr %r0 - blr - /* * int setfault() * diff --git a/sys/powerpc/include/rtas.h b/sys/powerpc/include/rtas.h new file mode 100644 index 00000000000..5b18632ce13 --- /dev/null +++ b/sys/powerpc/include/rtas.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_RTAS_H_ +#define _MACHINE_RTAS_H_ + +#include +#include +#include + +/* + * RTAS functions are defined by 32-bit integer tokens. These vary from + * system to system, and can be looked up from their standardized names + * using rtas_token_lookup(). If RTAS is not available, rtas_token_lookup() + * and rtas_call_method() return -1; this can be checked in advance using + * rtas_exists(). Otherwise, rtas_call_method() returns one of the RTAS + * status codes from the bottom of this file. + */ + +int rtas_exists(void); +int rtas_call_method(cell_t token, int nargs, int nreturns, ...); +cell_t rtas_token_lookup(const char *method); + +/* RTAS Status Codes: see CHRP or PAPR specification */ +#define RTAS_OK 0 +#define RTAS_HW_ERROR -1 +#define RTAS_BUSY -2 +#define RTAS_PARAM_ERROR -3 +#define RTAS_STATE_CHANGE -7 +#define RTAS_VENDOR_BEGIN 9000 +#define RTAS_EXTENDED_DELAY 9900 +#define RTAS_ISOLATION_ERROR -9000 +#define RTAS_VENDOR_ERROR_BEGIN -9004 + +#endif /* _MACHINE_RTAS_H_ */ + diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index 9af4051999a..f60243044bc 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -60,17 +60,15 @@ __FBSDID("$FreeBSD$"); #include #include -#define OFMEM_REGIONS 32 -static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; -static struct mem_region OFfree[OFMEM_REGIONS + 3]; -static int nOFmem; +static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ]; +static struct mem_region OFfree[PHYS_AVAIL_SZ]; extern register_t ofmsr[5]; -static int (*ofwcall)(void *); +extern void *openfirmware_entry; static void *fdt; int ofw_real_mode; -int ofw_32bit_mode_entry(void *); +int ofwcall(void *); static void ofw_quiesce(void); static int openfirmware(void *args); @@ -134,11 +132,32 @@ memr_merge(struct mem_region *from, struct mem_region *to) to->mr_size = end - to->mr_start; } +/* + * Quick sort callout for comparing memory regions. + */ +static int mr_cmp(const void *a, const void *b); + +static int +mr_cmp(const void *a, const void *b) +{ + const struct mem_region *regiona; + const struct mem_region *regionb; + + regiona = a; + regionb = b; + if (regiona->mr_start < regionb->mr_start) + return (-1); + else if (regiona->mr_start > regionb->mr_start) + return (1); + else + return (0); +} + static int parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) { cell_t address_cells, size_cells; - cell_t OFmem[4*(OFMEM_REGIONS + 1)]; + cell_t OFmem[4 * PHYS_AVAIL_SZ]; int sz, i, j; int apple_hack_mode; phandle_t phandle; @@ -175,7 +194,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) * Get memory. */ if ((node == -1) || (sz = OF_getprop(node, prop, - OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0) + OFmem, sizeof(OFmem[0]) * 4 * PHYS_AVAIL_SZ)) <= 0) panic("Physical memory map not found"); i = 0; @@ -225,7 +244,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) #ifdef __powerpc64__ if (apple_hack_mode) { /* Add in regions above 4 GB to the available list */ - struct mem_region himem[OFMEM_REGIONS]; + struct mem_region himem[PHYS_AVAIL_SZ]; int hisz; hisz = parse_ofw_memory(node, "reg", himem); @@ -243,6 +262,81 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) return (sz); } +static int +parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, + struct mem_region *ofavail) +{ + phandle_t phandle; + vm_offset_t base; + int i, idx, len, lasz, lmsz, res; + uint32_t lmb_size[2]; + unsigned long *dmem, flags; + + lmsz = *msz; + lasz = *asz; + + phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); + if (phandle == -1) + /* No drconf node, return. */ + return (0); + + res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); + if (res == -1) + return (0); + + /* Parse the /ibm,dynamic-memory. + The first position gives the # of entries. The next two words + reflect the address of the memory block. The next four words are + the DRC index, reserved, list index and flags. + (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) + + #el Addr DRC-idx res list-idx flags + ------------------------------------------------- + | 4 | 8 | 4 | 4 | 4 | 4 |.... + ------------------------------------------------- + */ + + len = OF_getproplen(phandle, "ibm,dynamic-memory"); + if (len > 0) { + + /* We have to use a variable length array on the stack + since we have very limited stack space. + */ + cell_t arr[len/sizeof(cell_t)]; + + res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, + sizeof(arr)); + if (res == -1) + return (0); + + /* Number of elements */ + idx = arr[0]; + + /* First address. */ + dmem = (void*)&arr[1]; + + for (i = 0; i < idx; i++) { + base = *dmem; + dmem += 2; + flags = *dmem; + /* Use region only if available and not reserved. */ + if ((flags & 0x8) && !(flags & 0x80)) { + ofmem[lmsz].mr_start = base; + ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; + ofavail[lasz].mr_start = base; + ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; + lmsz++; + lasz++; + } + dmem++; + } + } + + *msz = lmsz; + *asz = lasz; + + return (1); +} /* * This is called during powerpc_init, before the system is really initialized. * It shall provide the total and the available regions of RAM. @@ -255,31 +349,62 @@ ofw_mem_regions(struct mem_region **memp, int *memsz, struct mem_region **availp, int *availsz) { phandle_t phandle; + vm_offset_t maxphysaddr; int asz, msz, fsz; - int i, j; + int i, j, res; int still_merging; + char name[31]; asz = msz = 0; /* - * Get memory. + * Get memory from all the /memory nodes. */ - phandle = OF_finddevice("/memory"); - if (phandle == -1) - phandle = OF_finddevice("/memory@0"); + for (phandle = OF_child(OF_peer(0)); phandle != 0; + phandle = OF_peer(phandle)) { + if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) + continue; + if (strncmp(name, "memory", sizeof(name)) != 0) + continue; - msz = parse_ofw_memory(phandle, "reg", OFmem); - nOFmem = msz / sizeof(struct mem_region); - asz = parse_ofw_memory(phandle, "available", OFavail); + res = parse_ofw_memory(phandle, "reg", &OFmem[msz]); + msz += res/sizeof(struct mem_region); + if (OF_getproplen(phandle, "available") >= 0) + res = parse_ofw_memory(phandle, "available", + &OFavail[asz]); + else + res = parse_ofw_memory(phandle, "reg", &OFavail[asz]); + asz += res/sizeof(struct mem_region); + } + + /* Check for memory in ibm,dynamic-reconfiguration-memory */ + parse_drconf_memory(&msz, &asz, OFmem, OFavail); + + qsort(OFmem, msz, sizeof(*OFmem), mr_cmp); + qsort(OFavail, asz, sizeof(*OFavail), mr_cmp); *memp = OFmem; - *memsz = nOFmem; - + *memsz = msz; + + /* + * On some firmwares (SLOF), some memory may be marked available that + * doesn't actually exist. This manifests as an extension of the last + * available segment past the end of physical memory, so truncate that + * one. + */ + maxphysaddr = 0; + for (i = 0; i < msz; i++) + if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr) + maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size; + + if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr) + OFavail[asz - 1].mr_size = maxphysaddr - + OFavail[asz - 1].mr_start; + /* * OFavail may have overlapping regions - collapse these * and copy out remaining regions to OFfree */ - asz /= sizeof(struct mem_region); do { still_merging = FALSE; for (i = 0; i < asz; i++) { @@ -318,19 +443,6 @@ OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) else ofw_real_mode = 1; - ofwcall = NULL; - - #ifdef __powerpc64__ - /* - * For PPC64, we need to use some hand-written - * asm trampolines to get to OF. - */ - if (openfirm != NULL) - ofwcall = ofw_32bit_mode_entry; - #else - ofwcall = openfirm; - #endif - fdt = fdt_ptr; #ifdef FDT_DTB_STATIC @@ -345,7 +457,7 @@ OF_bootstrap() { boolean_t status = FALSE; - if (ofwcall != NULL) { + if (openfirmware_entry != NULL) { if (ofw_real_mode) { status = OF_install(OFW_STD_REAL, 0); } else { @@ -481,12 +593,7 @@ openfirmware(void *args) int result; #ifdef SMP struct ofw_rv_args rv_args; - #endif - if (pmap_bootstrapped && ofw_real_mode) - args = (void *)pmap_kextract((vm_offset_t)args); - - #ifdef SMP rv_args.args = args; rv_args.in_progress = 1; smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, diff --git a/sys/powerpc/ofw/ofw_real.c b/sys/powerpc/ofw/ofw_real.c index 617f9bed4f2..1fc2ed10e61 100644 --- a/sys/powerpc/ofw/ofw_real.c +++ b/sys/powerpc/ofw/ofw_real.c @@ -205,13 +205,14 @@ ofw_real_bounce_alloc(void *junk) /* * Allocate a page of contiguous, wired physical memory that can - * fit into a 32-bit address space. + * fit into a 32-bit address space and accessed from real mode. */ mtx_lock(&of_bounce_mtx); - of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0, - 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE); + of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0, 0, + ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE, + PAGE_SIZE); of_bounce_phys = vtophys(of_bounce_virt); of_bounce_size = PAGE_SIZE; diff --git a/sys/powerpc/ofw/ofwcall32.S b/sys/powerpc/ofw/ofwcall32.S new file mode 100644 index 00000000000..06cc1055cd1 --- /dev/null +++ b/sys/powerpc/ofw/ofwcall32.S @@ -0,0 +1,154 @@ +/*- + * Copyright (C) 2009-2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 TOOLS GMBH 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$ + */ + +#include + +#include +#include +#include +#include + +#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ + +/* + * Globals + */ + .data +GLOBAL(ofmsr) + .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ +GLOBAL(rtasmsr) + .long 0 +GLOBAL(openfirmware_entry) + .long 0 /* Open Firmware entry point */ +GLOBAL(rtas_entry) + .long 0 /* RTAS entry point */ + + .align 4 +ofwstk: + .space OFWSTKSZ +rtas_regsave: + .space 4 + +/* + * Open Firmware Entry Point. May need to enter real mode. + * + * C prototype: int ofwcall(void *callbuffer); + */ + +ASENTRY(ofwcall) + mflr %r0 + stw %r0,4(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r4,openfirmware_entry@ha + lwz %r4,openfirmware_entry@l(%r4) + + /* + * Set the MSR to the OF value. This has the side effect of disabling + * exceptions, which prevents preemption later. + */ + + lis %r5,ofmsr@ha + lwz %r5,ofmsr@l(%r5) + mtmsr %r5 + isync + + /* + * Set up OF stack. This needs to be potentially accessible in real mode + * The pointer to the current kernel stack is placed at the very + * top of the stack along with the old MSR so we can get them back + * later. + */ + mr %r5,%r1 + lis %r1,(ofwstk+OFWSTKSZ-16)@ha + addi %r1,%r1,(ofwstk+OFWSTKSZ-16)@l + stw %r5,8(%r1) /* Save real stack pointer */ + stw %r6,12(%r1) /* Save old MSR */ + li %r5,0 + stw %r5,4(%r1) + stw %r5,0(%r1) + + /* Finally, branch to OF */ + mtctr %r4 + bctrl + + /* Reload stack pointer and MSR from the OFW stack */ + lwz %r6,12(%r1) + lwz %r1,8(%r1) + + /* Now set the real MSR */ + mtmsr %r6 + isync + + /* Return */ + lwz %r0,4(%r1) + mtlr %r0 + blr + +/* + * RTAS Entry Point. Similar to the OF one, but simpler (no separate stack) + * + * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); + */ + +ASENTRY(rtascall) + mflr %r0 + stw %r0,4(%r1) + + /* Record the old MSR to real-mode-accessible area */ + mfmsr %r0 + lis %r5,rtas_regsave@ha + stw %r0,rtas_regsave@l(%r5) + + /* read client interface handler */ + lis %r5,rtas_entry@ha + lwz %r5,rtas_entry@l(%r5) + + /* Set the MSR to the RTAS value */ + lis %r6,rtasmsr@ha + lwz %r6,rtasmsr@l(%r6) + mtmsr %r6 + isync + + /* Branch to RTAS */ + mtctr %r5 + bctrl + + /* Now set the MSR back */ + lis %r6,rtas_regsave@ha + lwz %r6,rtas_regsave@l(%r6) + mtmsr %r6 + isync + + /* And return */ + lwz %r0,4(%r1) + mtlr %r0 + blr + diff --git a/sys/powerpc/ofw/ofwcall64.S b/sys/powerpc/ofw/ofwcall64.S new file mode 100644 index 00000000000..1fb78e8a98b --- /dev/null +++ b/sys/powerpc/ofw/ofwcall64.S @@ -0,0 +1,290 @@ +/*- + * Copyright (C) 2009-2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 TOOLS GMBH 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$ + */ + +#include + +#include +#include +#include +#include + +#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ + +/* + * Globals + */ + .data + .align 4 +ofwstk: + .space OFWSTKSZ +rtas_regsave: + .space 24 /* 3 * sizeof(register_t) */ +GLOBAL(ofmsr) + .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ +GLOBAL(rtasmsr) + .llong 0 +GLOBAL(openfirmware_entry) + .llong 0 /* Open Firmware entry point */ +GLOBAL(rtas_entry) + .llong 0 /* RTAS entry point */ + +/* + * Open Firmware Real-mode Entry Point. This is a huge pain. + */ + +ASENTRY(ofwcall) + mflr %r0 + std %r0,16(%r1) + stdu %r1,-208(%r1) + + /* + * We need to save the following, because OF's register save/ + * restore code assumes that the contents of registers are + * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These + * get placed in that order in the stack. + */ + + mfcr %r4 + std %r4,48(%r1) + std %r13,56(%r1) + std %r14,64(%r1) + std %r15,72(%r1) + std %r16,80(%r1) + std %r17,88(%r1) + std %r18,96(%r1) + std %r19,104(%r1) + std %r20,112(%r1) + std %r21,120(%r1) + std %r22,128(%r1) + std %r23,136(%r1) + std %r24,144(%r1) + std %r25,152(%r1) + std %r26,160(%r1) + std %r27,168(%r1) + std %r28,176(%r1) + std %r29,184(%r1) + std %r30,192(%r1) + std %r31,200(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r4,openfirmware_entry@ha + ld %r4,openfirmware_entry@l(%r4) + + /* + * Set the MSR to the OF value. This has the side effect of disabling + * exceptions, which is important for the next few steps. + */ + + lis %r5,ofmsr@ha + ld %r5,ofmsr@l(%r5) + mtmsrd %r5 + isync + + /* + * Set up OF stack. This needs to be accessible in real mode and + * use the 32-bit ABI stack frame format. The pointer to the current + * kernel stack is placed at the very top of the stack along with + * the old MSR so we can get them back later. + */ + mr %r5,%r1 + lis %r1,(ofwstk+OFWSTKSZ-32)@ha + addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l + std %r5,8(%r1) /* Save real stack pointer */ + std %r2,16(%r1) /* Save old TOC */ + std %r6,24(%r1) /* Save old MSR */ + li %r5,0 + stw %r5,4(%r1) + stw %r5,0(%r1) + + /* Finally, branch to OF */ + mtctr %r4 + bctrl + + /* Reload stack pointer and MSR from the OFW stack */ + ld %r6,24(%r1) + ld %r2,16(%r1) + ld %r1,8(%r1) + + /* Now set the real MSR */ + mtmsrd %r6 + isync + + /* Sign-extend the return value from OF */ + extsw %r3,%r3 + + /* Restore all the non-volatile registers */ + ld %r5,48(%r1) + mtcr %r5 + ld %r13,56(%r1) + ld %r14,64(%r1) + ld %r15,72(%r1) + ld %r16,80(%r1) + ld %r17,88(%r1) + ld %r18,96(%r1) + ld %r19,104(%r1) + ld %r20,112(%r1) + ld %r21,120(%r1) + ld %r22,128(%r1) + ld %r23,136(%r1) + ld %r24,144(%r1) + ld %r25,152(%r1) + ld %r26,160(%r1) + ld %r27,168(%r1) + ld %r28,176(%r1) + ld %r29,184(%r1) + ld %r30,192(%r1) + ld %r31,200(%r1) + + /* Restore the stack and link register */ + ld %r1,0(%r1) + ld %r0,16(%r1) + mtlr %r0 + blr + +/* + * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate + * stack) + * + * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); + */ + +ASENTRY(rtascall) + mflr %r0 + std %r0,16(%r1) + stdu %r1,-208(%r1) + + /* + * We need to save the following, because RTAS's register save/ + * restore code assumes that the contents of registers are + * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These + * get placed in that order in the stack. + */ + + mfcr %r5 + std %r5,48(%r1) + std %r13,56(%r1) + std %r14,64(%r1) + std %r15,72(%r1) + std %r16,80(%r1) + std %r17,88(%r1) + std %r18,96(%r1) + std %r19,104(%r1) + std %r20,112(%r1) + std %r21,120(%r1) + std %r22,128(%r1) + std %r23,136(%r1) + std %r24,144(%r1) + std %r25,152(%r1) + std %r26,160(%r1) + std %r27,168(%r1) + std %r28,176(%r1) + std %r29,184(%r1) + std %r30,192(%r1) + std %r31,200(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r5,rtas_entry@ha + ld %r5,rtas_entry@l(%r5) + + /* + * Set the MSR to the RTAS value. This has the side effect of disabling + * exceptions, which is important for the next few steps. + */ + + lis %r7,rtasmsr@ha + ld %r7,rtasmsr@l(%r7) + mtmsrd %r7 + isync + + /* + * Set up RTAS register save area, so that we can get back all of + * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR. + * Put this in r1, since RTAS is obliged to save it. Kernel globals + * are below 4 GB, so this is safe. + */ + mr %r7,%r1 + lis %r1,rtas_regsave@ha + addi %r1,%r1,rtas_regsave@l + std %r7,0(%r1) /* Save 64-bit stack pointer */ + std %r2,8(%r1) /* Save TOC */ + std %r6,16(%r1) /* Save MSR */ + + /* Finally, branch to RTAS */ + mtctr %r5 + bctrl + + /* + * Reload stack pointer and MSR from the reg save area in r1. We are + * running in 32-bit mode at this point, so it doesn't matter if r1 + * has become sign-extended. + */ + ld %r6,16(%r1) + ld %r2,8(%r1) + ld %r1,0(%r1) + + /* Now set the real MSR */ + mtmsrd %r6 + isync + + /* Sign-extend the return value from RTAS */ + extsw %r3,%r3 + + /* Restore all the non-volatile registers */ + ld %r5,48(%r1) + mtcr %r5 + ld %r13,56(%r1) + ld %r14,64(%r1) + ld %r15,72(%r1) + ld %r16,80(%r1) + ld %r17,88(%r1) + ld %r18,96(%r1) + ld %r19,104(%r1) + ld %r20,112(%r1) + ld %r21,120(%r1) + ld %r22,128(%r1) + ld %r23,136(%r1) + ld %r24,144(%r1) + ld %r25,152(%r1) + ld %r26,160(%r1) + ld %r27,168(%r1) + ld %r28,176(%r1) + ld %r29,184(%r1) + ld %r30,192(%r1) + ld %r31,200(%r1) + + /* Restore the stack and link register */ + ld %r1,0(%r1) + ld %r0,16(%r1) + mtlr %r0 + blr + diff --git a/sys/powerpc/aim/ofwmagic.S b/sys/powerpc/ofw/ofwmagic.S similarity index 100% rename from sys/powerpc/aim/ofwmagic.S rename to sys/powerpc/ofw/ofwmagic.S diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c new file mode 100644 index 00000000000..59692c9b953 --- /dev/null +++ b/sys/powerpc/ofw/rtas.c @@ -0,0 +1,243 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +MALLOC_DEFINE(M_RTAS, "rtas", "Run Time Abstraction Service"); + +static vm_offset_t rtas_bounce_phys; +static caddr_t rtas_bounce_virt; +static off_t rtas_bounce_offset; +static size_t rtas_bounce_size; +static uintptr_t rtas_private_data; +static struct mtx rtas_mtx; +static phandle_t rtas; + +/* From ofwcall.S */ +int rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat); +extern uintptr_t rtas_entry; +extern register_t rtasmsr; + +/* + * After the VM is up, allocate RTAS memory and instantiate it + */ + +static void rtas_setup(void *); + +SYSINIT(rtas_setup, SI_SUB_KMEM, SI_ORDER_ANY, rtas_setup, NULL); + +static void +rtas_setup(void *junk) +{ + ihandle_t rtasi; + cell_t rtas_size = 0, rtas_ptr; + char path[31]; + int result; + + rtas = OF_finddevice("/rtas"); + if (rtas == -1) { + rtas = 0; + return; + } + OF_package_to_path(rtas, path, sizeof(path)); + rtasi = OF_open(path); + if (rtasi == 0) { + rtas = 0; + printf("Error initializing RTAS: could not open node\n"); + return; + } + + mtx_init(&rtas_mtx, "RTAS", MTX_DEF, 0); + + /* RTAS must be called with everything turned off in MSR */ + rtasmsr = mfmsr(); + rtasmsr &= ~(PSL_IR | PSL_DR | PSL_EE | PSL_SE); + #ifdef __powerpc64__ + rtasmsr &= ~PSL_SF; + #endif + + /* + * Allocate rtas_size + one page of contiguous, wired physical memory + * that can fit into a 32-bit address space and accessed from real mode. + * This is used both to bounce arguments and for RTAS private data. + * + * It must be 4KB-aligned and not cross a 256 MB boundary. + */ + + OF_getprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size)); + rtas_size = round_page(rtas_size); + rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0, + ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), + 4096, 256*1024*1024); + + rtas_private_data = vtophys(rtas_bounce_virt); + rtas_bounce_virt += rtas_size; /* Actual bounce area */ + rtas_bounce_phys = vtophys(rtas_bounce_virt); + rtas_bounce_size = PAGE_SIZE; + + /* + * Instantiate RTAS. We always use the 32-bit version. + */ + + result = OF_call_method("instantiate-rtas", rtasi, 1, 1, + (cell_t)rtas_private_data, &rtas_ptr); + OF_close(rtasi); + + if (result != 0) { + rtas = 0; + rtas_ptr = 0; + printf("Error initializing RTAS (%d)\n", result); + return; + } + + rtas_entry = (uintptr_t)(rtas_ptr); +} + +static cell_t +rtas_real_map(const void *buf, size_t len) +{ + cell_t phys; + + mtx_assert(&rtas_mtx, MA_OWNED); + + /* + * Make sure the bounce page offset satisfies any reasonable + * alignment constraint. + */ + rtas_bounce_offset += sizeof(register_t) - + (rtas_bounce_offset % sizeof(register_t)); + + if (rtas_bounce_offset + len > rtas_bounce_size) { + panic("Oversize RTAS call!"); + return 0; + } + + if (buf != NULL) + memcpy(rtas_bounce_virt + rtas_bounce_offset, buf, len); + else + return (0); + + phys = rtas_bounce_phys + rtas_bounce_offset; + rtas_bounce_offset += len; + + return (phys); +} + +static void +rtas_real_unmap(cell_t physaddr, void *buf, size_t len) +{ + mtx_assert(&rtas_mtx, MA_OWNED); + + if (physaddr == 0) + return; + + memcpy(buf, rtas_bounce_virt + (physaddr - rtas_bounce_phys), len); +} + +/* Check if we have RTAS */ +int +rtas_exists(void) +{ + return (rtas != 0); +} + +/* Call an RTAS method by token */ +int +rtas_call_method(cell_t token, int nargs, int nreturns, ...) +{ + vm_offset_t argsptr; + va_list ap; + struct { + cell_t token; + cell_t nargs; + cell_t nreturns; + cell_t args_n_results[12]; + } args; + int n, result; + + if (!rtas_exists() || nargs + nreturns > 12) + return (-1); + + args.token = token; + va_start(ap, nreturns); + + mtx_lock(&rtas_mtx); + rtas_bounce_offset = 0; + + args.nargs = nargs; + args.nreturns = nreturns; + + for (n = 0; n < nargs; n++) + args.args_n_results[n] = va_arg(ap, cell_t); + + argsptr = rtas_real_map(&args, sizeof(args)); + result = rtascall(argsptr, rtas_private_data); + rtas_real_unmap(argsptr, &args, sizeof(args)); + mtx_unlock(&rtas_mtx); + + if (result < 0) + return (result); + + for (n = nargs; n < nargs + nreturns; n++) + *va_arg(ap, cell_t *) = args.args_n_results[n]; + return (result); +} + +/* Look up an RTAS token */ +cell_t +rtas_token_lookup(const char *method) +{ + cell_t token; + + if (!rtas_exists()) + return (-1); + + if (OF_getprop(rtas, method, &token, sizeof(token)) == -1) + return (-1); + + return (token); +} + + From 97f7cde42c61bb34be5cc7cdc5dfe126aef8e5fb Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:15:44 +0000 Subject: [PATCH 03/31] Remove some dead code: unnecessary isyncs and memory sorting, which are handled in mtmsr() and mem_regions(), respectively. --- sys/powerpc/aim/interrupt.c | 4 +--- sys/powerpc/aim/mmu_oea.c | 20 +------------------- sys/powerpc/aim/mmu_oea64.c | 26 ++++---------------------- sys/powerpc/aim/moea64_native.c | 6 +++--- 4 files changed, 9 insertions(+), 47 deletions(-) diff --git a/sys/powerpc/aim/interrupt.c b/sys/powerpc/aim/interrupt.c index b06fb92e233..d1e36551458 100644 --- a/sys/powerpc/aim/interrupt.c +++ b/sys/powerpc/aim/interrupt.c @@ -100,10 +100,8 @@ powerpc_interrupt(struct trapframe *framep) default: /* Re-enable interrupts if applicable. */ ee = framep->srr1 & PSL_EE; - if (ee != 0) { + if (ee != 0) mtmsr(mfmsr() | ee); - isync(); - } trap(framep); } } diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 30435f527fd..51c6f8a0dc9 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -584,25 +584,8 @@ moea_pte_change(struct pte *pt, struct pte *pvo_pt, vm_offset_t va) /* * Quick sort callout for comparing memory regions. */ -static int mr_cmp(const void *a, const void *b); static int om_cmp(const void *a, const void *b); -static int -mr_cmp(const void *a, const void *b) -{ - const struct mem_region *regiona; - const struct mem_region *regionb; - - regiona = a; - regionb = b; - if (regiona->mr_start < regionb->mr_start) - return (-1); - else if (regiona->mr_start > regionb->mr_start) - return (1); - else - return (0); -} - static int om_cmp(const void *a, const void *b) { @@ -720,7 +703,6 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) mem_regions(&pregions, &pregions_sz, ®ions, ®ions_sz); CTR0(KTR_PMAP, "moea_bootstrap: physical memory"); - qsort(pregions, pregions_sz, sizeof(*pregions), mr_cmp); for (i = 0; i < pregions_sz; i++) { vm_offset_t pa; vm_offset_t end; @@ -749,7 +731,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) if (sizeof(phys_avail)/sizeof(phys_avail[0]) < regions_sz) panic("moea_bootstrap: phys_avail too small"); - qsort(regions, regions_sz, sizeof(*regions), mr_cmp); + phys_avail_count = 0; physsz = 0; hwphyssz = 0; diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index c33a0941c39..bd7b7091bf2 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -162,8 +162,8 @@ __FBSDID("$FreeBSD$"); void moea64_release_vsid(uint64_t vsid); uintptr_t moea64_get_unique_vsid(void); -#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR); isync() -#define ENABLE_TRANS(msr) mtmsr(msr); isync() +#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR) +#define ENABLE_TRANS(msr) mtmsr(msr) #define VSID_MAKE(sr, hash) ((sr) | (((hash) & 0xfffff) << 4)) #define VSID_TO_HASH(vsid) (((vsid) >> 4) & 0xfffff) @@ -473,25 +473,8 @@ moea64_calc_wimg(vm_offset_t pa, vm_memattr_t ma) /* * Quick sort callout for comparing memory regions. */ -static int mr_cmp(const void *a, const void *b); static int om_cmp(const void *a, const void *b); -static int -mr_cmp(const void *a, const void *b) -{ - const struct mem_region *regiona; - const struct mem_region *regionb; - - regiona = a; - regionb = b; - if (regiona->mr_start < regionb->mr_start) - return (-1); - else if (regiona->mr_start > regionb->mr_start) - return (1); - else - return (0); -} - static int om_cmp(const void *a, const void *b) { @@ -707,10 +690,9 @@ moea64_early_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelen mem_regions(&pregions, &pregions_sz, ®ions, ®ions_sz); CTR0(KTR_PMAP, "moea64_bootstrap: physical memory"); - qsort(pregions, pregions_sz, sizeof(*pregions), mr_cmp); if (sizeof(phys_avail)/sizeof(phys_avail[0]) < regions_sz) panic("moea64_bootstrap: phys_avail too small"); - qsort(regions, regions_sz, sizeof(*regions), mr_cmp); + phys_avail_count = 0; physsz = 0; hwphyssz = 0; @@ -895,7 +877,7 @@ moea64_late_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend * Initialize MMU and remap early physical mappings */ MMU_CPU_BOOTSTRAP(mmup,0); - mtmsr(mfmsr() | PSL_DR | PSL_IR); isync(); + mtmsr(mfmsr() | PSL_DR | PSL_IR); pmap_bootstrapped++; bs_remap_earlyboot(); diff --git a/sys/powerpc/aim/moea64_native.c b/sys/powerpc/aim/moea64_native.c index bca51ab4d2e..9e5174fcbba 100644 --- a/sys/powerpc/aim/moea64_native.c +++ b/sys/powerpc/aim/moea64_native.c @@ -185,8 +185,8 @@ TLBIE(uint64_t vpn) { mtx_unlock_spin(&tlbie_mutex); } -#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR); isync() -#define ENABLE_TRANS(msr) mtmsr(msr); isync() +#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR) +#define ENABLE_TRANS(msr) mtmsr(msr) /* * PTEG data. @@ -344,7 +344,7 @@ moea64_cpu_bootstrap_native(mmu_t mmup, int ap) * Initialize segment registers and MMU */ - mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR); isync(); + mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR); /* * Install kernel SLB entries From 6dd24ab3f14666223ecb8b235f76be9a26ab5d7b Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:19:18 +0000 Subject: [PATCH 04/31] Include the modules area in the mapped kernel code. This fixes the kernel's access to modules and loader metadata when started from real mode, but without a direct map. --- sys/powerpc/aim/machdep.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 65c9db1dae3..9dd5f329abc 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -251,7 +251,6 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, vm_offset_t basekernel, void *mdp) { struct pcpu *pc; - vm_offset_t end; void *generictrap; size_t trap_offset; void *kmdp; @@ -263,7 +262,6 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, int ppc64; #endif - end = 0; kmdp = NULL; trap_offset = 0; cacheline_warn = 0; @@ -279,7 +277,8 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, if (kmdp != NULL) { boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); - end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); + endkernel = ulmax(endkernel, MD_FETCH(kmdp, + MODINFOMD_KERNEND, vm_offset_t)); #ifdef DDB ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); From 20ae1015b9029b34737f38d66992019e480a74fe Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:21:20 +0000 Subject: [PATCH 05/31] Explicitly initialize the first thread's MSR to PSL_KERNSET. --- sys/powerpc/aim/machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 9dd5f329abc..aa8885a594f 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -526,7 +526,7 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, pmap_mmu_install(MMU_TYPE_OEA, BUS_PROBE_GENERIC); pmap_bootstrap(startkernel, endkernel); - mtmsr(mfmsr() | PSL_IR|PSL_DR|PSL_ME|PSL_RI); + mtmsr(PSL_KERNSET & ~PSL_EE); isync(); /* From 0d7136ba72646b2cac846fcf403d4b2f2c0f6ba0 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:22:00 +0000 Subject: [PATCH 06/31] Missed file in r222613. --- sys/conf/files.powerpc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 7d4e2a2a796..9dcc8678601 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -87,7 +87,6 @@ powerpc/aim/moea64_if.m optional aim powerpc/aim/moea64_native.c optional aim powerpc/aim/mp_cpudep.c optional aim smp powerpc/aim/nexus.c optional aim -powerpc/aim/ofwmagic.S optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/aim/swtch32.S optional aim powerpc powerpc/aim/swtch64.S optional aim powerpc64 @@ -137,6 +136,10 @@ powerpc/ofw/ofw_pcibus.c optional pci aim powerpc/ofw/ofw_pcib_pci.c optional pci aim powerpc/ofw/ofw_real.c optional aim powerpc/ofw/ofw_syscons.c optional sc aim +powerpc/ofw/ofwcall32.S optional aim powerpc +powerpc/ofw/ofwcall64.S optional aim powerpc64 +powerpc/ofw/ofwmagic.S optional aim +powerpc/ofw/rtas.c optional aim powerpc/powermac/ata_kauai.c optional powermac ata | powermac atamacio powerpc/powermac/ata_macio.c optional powermac ata | powermac atamacio powerpc/powermac/ata_dbdma.c optional powermac ata | powermac atamacio From 1dff98d9bbbc74fb07937a4d6d3eaf5f4101c8c5 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:23:36 +0000 Subject: [PATCH 07/31] If running under a hypervisor, don't yell at the user about starting unknown CPU types, instead relying on the hypervisor to have given us a reasonable environment. --- sys/powerpc/aim/mp_cpudep.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/powerpc/aim/mp_cpudep.c b/sys/powerpc/aim/mp_cpudep.c index 3ee22f3e412..d617fdec564 100644 --- a/sys/powerpc/aim/mp_cpudep.c +++ b/sys/powerpc/aim/mp_cpudep.c @@ -87,7 +87,6 @@ cpudep_ap_bootstrap(void) msr = PSL_KERNSET & ~PSL_EE; mtmsr(msr); - isync(); pcpup->pc_curthread = pcpup->pc_idlethread; pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; @@ -344,6 +343,10 @@ cpudep_ap_setup() break; default: +#ifdef __powerpc64__ + if (!(mfmsr() & PSL_HV)) /* Rely on HV to have set things up */ + break; +#endif printf("WARNING: Unknown CPU type. Cache performace may be " "suboptimal.\n"); break; From d63d020e223ab9f7bf66725a98dfe745fb923e80 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Thu, 2 Jun 2011 14:25:27 +0000 Subject: [PATCH 08/31] Write the multi step netconfig to a temporary file and only move that to the final name if netconfig was completely finished. This fixes reentrance problems even better than r222611. Suggested by: nwhitehorn Reviewed by: nwhitehorn Sponsored by: The FreeBSD Foundation Sponsored by: iXsystems --- usr.sbin/bsdinstall/scripts/netconfig | 7 ++++--- usr.sbin/bsdinstall/scripts/netconfig_ipv4 | 6 +++--- usr.sbin/bsdinstall/scripts/netconfig_ipv6 | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig index d8984e27f79..37fe8c65dbe 100755 --- a/usr.sbin/bsdinstall/scripts/netconfig +++ b/usr.sbin/bsdinstall/scripts/netconfig @@ -54,14 +54,14 @@ INTERFACE=`echo $DIALOG_TAGS | xargs dialog --backtitle 'FreeBSD Installer' --ti if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi exec 3>&- -: > $BSDINSTALL_TMPETC/rc.conf.net +: > $BSDINSTALL_TMPETC/._rc.conf.net # Do a dirty check to see if this a wireless interface -- there should be a # better way IFCONFIG_PREFIX="" if ifconfig $INTERFACE | grep -q 'media: IEEE 802.11 Wireless'; then NEXT_WLAN_IFACE=wlan0 # XXX - echo wlans_$INTERFACE=\"$NEXT_WLAN_IFACE\" >> $BSDINSTALL_TMPETC/rc.conf.net + echo wlans_$INTERFACE=\"$NEXT_WLAN_IFACE\" >> $BSDINSTALL_TMPETC/._rc.conf.net IFCONFIG_PREFIX="WPA " if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then ifconfig $NEXT_WLAN_IFACE create wlandev $INTERFACE @@ -95,7 +95,7 @@ fi # In case wlanconfig left an option and we do not support IPv4 we need to write # it out on its own. We cannot write it out with IPv6 as that suffix. if [ ${IPV4_AVAIL} -eq 0 -a -n ${IFCONFIG_PREFIX} ]; then - echo ifconfig_${INTERFACE}=\"${IFCONFIG_PREFIX}\" >> $BSDINSTALL_TMPETC/rc.conf.net + echo ifconfig_${INTERFACE}=\"${IFCONFIG_PREFIX}\" >> $BSDINSTALL_TMPETC/._rc.conf.net fi if [ ${IPV6_AVAIL} -eq 1 ]; then dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \ @@ -192,3 +192,4 @@ BEGIN { printf "nameserver %s\n", $1; }' > ${BSDINSTALL_TMPETC}/resolv.conf +mv $BSDINSTALL_TMPETC/._rc.conf.net $BSDINSTALL_TMPETC/rc.conf.net diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv4 b/usr.sbin/bsdinstall/scripts/netconfig_ipv4 index dc6da7ebdc9..72dc0ee8ad9 100755 --- a/usr.sbin/bsdinstall/scripts/netconfig_ipv4 +++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv4 @@ -44,7 +44,7 @@ esac dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0 if [ $? -eq $DIALOG_OK ]; then - echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/rc.conf.net + echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/._rc.conf.net if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0 @@ -74,10 +74,10 @@ echo $INTERFACE $IF_CONFIG | awk -v prefix="$IFCONFIG_PREFIX" '{ printf("ifconfig_%s=\"%s inet %s netmask %s\"\n", $1, prefix, $2, $3); printf("defaultrouter=\"%s\"\n", $4); - }' >> $BSDINSTALL_TMPETC/rc.conf.net + }' >> $BSDINSTALL_TMPETC/._rc.conf.net if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then - . $BSDINSTALL_TMPETC/rc.conf.net + . $BSDINSTALL_TMPETC/._rc.conf.net ifconfig $INTERFACE inet `eval echo \\\$ifconfig_$INTERFACE` route delete -inet default route add -inet default $defaultrouter diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv6 b/usr.sbin/bsdinstall/scripts/netconfig_ipv6 index c9fad5420d6..70bd203e19d 100755 --- a/usr.sbin/bsdinstall/scripts/netconfig_ipv6 +++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv6 @@ -69,7 +69,7 @@ while : ; do continue fi fi - echo ifconfig_${INTERFACE}_ipv6=\"inet6 accept_rtadv\" >> $BSDINSTALL_TMPETC/rc.conf.net + echo ifconfig_${INTERFACE}_ipv6=\"inet6 accept_rtadv\" >> $BSDINSTALL_TMPETC/._rc.conf.net exit 0 else break @@ -138,10 +138,10 @@ BEGIN { sub("$", "/64", $1); } printf("ifconfig_%s_ipv6=\"inet6 %s\"\n", iface, $1); -}' >> $BSDINSTALL_TMPETC/rc.conf.net +}' >> $BSDINSTALL_TMPETC/._rc.conf.net if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then - . $BSDINSTALL_TMPETC/rc.conf.net + . $BSDINSTALL_TMPETC/._rc.conf.net ifconfig ${INTERFACE} `eval echo \\\$ifconfig_${INTERFACE}_ipv6` route delete default route add default ${ipv6_defaultrouter} From 17763042e4fd3df8b6476726c2623e53346bf174 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 14:25:52 +0000 Subject: [PATCH 09/31] The POWER7 has only 32 SLB slots instead of 64, like other supported 64-bit PowerPC CPUs. Add infrastructure to support variable numbers of SLB slots and move the user slot from 63 to 0, so that it is always available. --- sys/powerpc/aim/machdep.c | 22 ++++++++++------- sys/powerpc/aim/slb.c | 26 ++++++++++++-------- sys/powerpc/aim/trap_subr64.S | 46 +++++++++++++++++------------------ sys/powerpc/include/slb.h | 2 +- 4 files changed, 52 insertions(+), 44 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index aa8885a594f..3ccae91add5 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -132,6 +132,7 @@ extern vm_offset_t ksym_start, ksym_end; int cold = 1; #ifdef __powerpc64__ +extern int n_slbs; int cacheline_size = 128; #else int cacheline_size = 32; @@ -337,13 +338,13 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, kdb_init(); - /* - * PowerPC 970 CPUs have a misfeature requested by Apple that makes - * them pretend they have a 32-byte cacheline. Turn this off - * before we measure the cacheline size. - */ - + /* Various very early CPU fix ups */ switch (mfpvr() >> 16) { + /* + * PowerPC 970 CPUs have a misfeature requested by Apple that + * makes them pretend they have a 32-byte cacheline. Turn this + * off before we measure the cacheline size. + */ case IBM970: case IBM970FX: case IBM970MP: @@ -352,6 +353,12 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, scratch &= ~HID5_970_DCBZ_SIZE_HI; mtspr(SPR_HID5, scratch); break; + #ifdef __powerpc64__ + case IBMPOWER7: + /* XXX: get from ibm,slb-size in device tree */ + n_slbs = 32; + break; + #endif } /* @@ -367,7 +374,6 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, msr = mfmsr(); mtmsr((msr & ~(PSL_IR | PSL_DR)) | PSL_RI); - isync(); /* * Measure the cacheline size using dcbz @@ -502,7 +508,6 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, * Restore MSR */ mtmsr(msr); - isync(); /* Warn if cachline size was not determined */ if (cacheline_warn == 1) { @@ -527,7 +532,6 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, pmap_bootstrap(startkernel, endkernel); mtmsr(PSL_KERNSET & ~PSL_EE); - isync(); /* * Initialize params/tunables that are derived from memsize diff --git a/sys/powerpc/aim/slb.c b/sys/powerpc/aim/slb.c index 1fafbb4fd08..df493b49fd9 100644 --- a/sys/powerpc/aim/slb.c +++ b/sys/powerpc/aim/slb.c @@ -51,8 +51,9 @@ uintptr_t moea64_get_unique_vsid(void); void moea64_release_vsid(uint64_t vsid); static void slb_zone_init(void *); -uma_zone_t slbt_zone; -uma_zone_t slb_cache_zone; +static uma_zone_t slbt_zone; +static uma_zone_t slb_cache_zone; +int n_slbs = 64; SYSINIT(slb_zone_init, SI_SUB_KMEM, SI_ORDER_ANY, slb_zone_init, NULL); @@ -426,16 +427,18 @@ slb_insert_kernel(uint64_t slbe, uint64_t slbv) /* Check for an unused slot, abusing the user slot as a full flag */ if (slbcache[USER_SLB_SLOT].slbe == 0) { - for (i = 0; i < USER_SLB_SLOT; i++) { + for (i = 0; i < n_slbs; i++) { + if (i == USER_SLB_SLOT) + continue; if (!(slbcache[i].slbe & SLBE_VALID)) goto fillkernslb; } - if (i == USER_SLB_SLOT) + if (i == n_slbs) slbcache[USER_SLB_SLOT].slbe = 1; } - for (i = mftb() % 64, j = 0; j < 64; j++, i = (i+1) % 64) { + for (i = mftb() % n_slbs, j = 0; j < n_slbs; j++, i = (i+1) % n_slbs) { if (i == USER_SLB_SLOT) continue; @@ -443,9 +446,11 @@ slb_insert_kernel(uint64_t slbe, uint64_t slbv) break; } - KASSERT(j < 64, ("All kernel SLB slots locked!")); + KASSERT(j < n_slbs, ("All kernel SLB slots locked!")); fillkernslb: + KASSERT(i != USER_SLB_SLOT, + ("Filling user SLB slot with a kernel mapping")); slbcache[i].slbv = slbv; slbcache[i].slbe = slbe | (uint64_t)i; @@ -466,11 +471,11 @@ slb_insert_user(pmap_t pm, struct slb *slb) PMAP_LOCK_ASSERT(pm, MA_OWNED); - if (pm->pm_slb_len < 64) { + if (pm->pm_slb_len < n_slbs) { i = pm->pm_slb_len; pm->pm_slb_len++; } else { - i = mftb() % 64; + i = mftb() % n_slbs; } /* Note that this replacement is atomic with respect to trap_subr */ @@ -521,8 +526,9 @@ slb_zone_init(void *dummy) slbt_zone = uma_zcreate("SLB tree node", sizeof(struct slbtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); - slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb *), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); + slb_cache_zone = uma_zcreate("SLB cache", + (n_slbs + 1)*sizeof(struct slb *), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, UMA_ZONE_VM); if (platform_real_maxaddr() != VM_MAX_ADDRESS) { uma_zone_set_allocf(slb_cache_zone, slb_uma_real_alloc); diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index 7156edb45f8..5d4148a55d8 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -53,55 +53,53 @@ * User SRs are loaded through a pointer to the current pmap. */ restore_usersrs: - GET_CPUINFO(%r28); - ld %r28,PC_USERSLB(%r28); + GET_CPUINFO(%r28) + ld %r28,PC_USERSLB(%r28) li %r29, 0 /* Set the counter to zero */ slbia slbmfee %r31,%r29 clrrdi %r31,%r31,28 slbie %r31 -instuserslb: - ld %r31, 0(%r28); /* Load SLB entry pointer */ - cmpli 0, %r31, 0; /* If NULL, stop */ - beqlr; +1: ld %r31, 0(%r28) /* Load SLB entry pointer */ + cmpli 0, %r31, 0 /* If NULL, stop */ + beqlr ld %r30, 0(%r31) /* Load SLBV */ ld %r31, 8(%r31) /* Load SLBE */ or %r31, %r31, %r29 /* Set SLBE slot */ - slbmte %r30, %r31; /* Install SLB entry */ + slbmte %r30, %r31 /* Install SLB entry */ - addi %r28, %r28, 8; /* Advance pointer */ - addi %r29, %r29, 1; - cmpli 0, %r29, 64; /* Repeat if we are not at the end */ - blt instuserslb; - blr; + addi %r28, %r28, 8 /* Advance pointer */ + addi %r29, %r29, 1 + b 1b /* Repeat */ /* * Kernel SRs are loaded directly from the PCPU fields */ restore_kernsrs: - GET_CPUINFO(%r28); - addi %r28,%r28,PC_KERNSLB; + GET_CPUINFO(%r28) + addi %r28,%r28,PC_KERNSLB li %r29, 0 /* Set the counter to zero */ slbia slbmfee %r31,%r29 clrrdi %r31,%r31,28 slbie %r31 -instkernslb: - ld %r31, 8(%r28); /* Load SLBE */ +1: cmpli 0, %r29, USER_SLB_SLOT /* Skip the user slot */ + beq- 2f - cmpli 0, %r31, 0; /* If SLBE is not valid, stop */ - beqlr; + ld %r31, 8(%r28) /* Load SLBE */ + cmpli 0, %r31, 0 /* If SLBE is not valid, stop */ + beqlr ld %r30, 0(%r28) /* Load SLBV */ - slbmte %r30, %r31; /* Install SLB entry */ + slbmte %r30, %r31 /* Install SLB entry */ - addi %r28, %r28, 16; /* Advance pointer */ - addi %r29, %r29, 1; - cmpli 0, %r29, USER_SLB_SLOT; /* Repeat if we are not at the end */ - blt instkernslb; - blr; +2: addi %r28, %r28, 16 /* Advance pointer */ + addi %r29, %r29, 1 + cmpli 0, %r29, 64 /* Repeat if we are not at the end */ + blt 1b + blr /* * FRAME_SETUP assumes: diff --git a/sys/powerpc/include/slb.h b/sys/powerpc/include/slb.h index f675e156b22..637110c6853 100644 --- a/sys/powerpc/include/slb.h +++ b/sys/powerpc/include/slb.h @@ -65,7 +65,7 @@ /* * User segment for copyin/out */ -#define USER_SLB_SLOT 63 +#define USER_SLB_SLOT 0 #define USER_SLB_SLBE (((USER_ADDR >> ADDR_SR_SHFT) << SLBE_ESID_SHIFT) | \ SLBE_VALID | USER_SLB_SLOT) From 48174c14b552af1d45b1fa074b2d3ba1e3c47dfb Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Thu, 2 Jun 2011 17:43:17 +0000 Subject: [PATCH 10/31] Temporarily back out those parts of r222613 related to parsing the memory map. They cause non-understood boot failures on some Apple machines with more than 2 GB of RAM (like my work desktop). --- sys/powerpc/ofw/ofw_machdep.c | 169 +++++----------------------------- 1 file changed, 25 insertions(+), 144 deletions(-) diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index f60243044bc..2f1e770941d 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -60,15 +60,18 @@ __FBSDID("$FreeBSD$"); #include #include -static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ]; -static struct mem_region OFfree[PHYS_AVAIL_SZ]; +#define OFMEM_REGIONS 32 +static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; +static struct mem_region OFfree[OFMEM_REGIONS + 3]; +static int nOFmem; extern register_t ofmsr[5]; +int ofwcall(void *); extern void *openfirmware_entry; static void *fdt; int ofw_real_mode; -int ofwcall(void *); +int ofw_32bit_mode_entry(void *); static void ofw_quiesce(void); static int openfirmware(void *args); @@ -132,32 +135,11 @@ memr_merge(struct mem_region *from, struct mem_region *to) to->mr_size = end - to->mr_start; } -/* - * Quick sort callout for comparing memory regions. - */ -static int mr_cmp(const void *a, const void *b); - -static int -mr_cmp(const void *a, const void *b) -{ - const struct mem_region *regiona; - const struct mem_region *regionb; - - regiona = a; - regionb = b; - if (regiona->mr_start < regionb->mr_start) - return (-1); - else if (regiona->mr_start > regionb->mr_start) - return (1); - else - return (0); -} - static int parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) { cell_t address_cells, size_cells; - cell_t OFmem[4 * PHYS_AVAIL_SZ]; + cell_t OFmem[4*(OFMEM_REGIONS + 1)]; int sz, i, j; int apple_hack_mode; phandle_t phandle; @@ -194,7 +176,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) * Get memory. */ if ((node == -1) || (sz = OF_getprop(node, prop, - OFmem, sizeof(OFmem[0]) * 4 * PHYS_AVAIL_SZ)) <= 0) + OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0) panic("Physical memory map not found"); i = 0; @@ -244,7 +226,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) #ifdef __powerpc64__ if (apple_hack_mode) { /* Add in regions above 4 GB to the available list */ - struct mem_region himem[PHYS_AVAIL_SZ]; + struct mem_region himem[OFMEM_REGIONS]; int hisz; hisz = parse_ofw_memory(node, "reg", himem); @@ -262,81 +244,6 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) return (sz); } -static int -parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, - struct mem_region *ofavail) -{ - phandle_t phandle; - vm_offset_t base; - int i, idx, len, lasz, lmsz, res; - uint32_t lmb_size[2]; - unsigned long *dmem, flags; - - lmsz = *msz; - lasz = *asz; - - phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); - if (phandle == -1) - /* No drconf node, return. */ - return (0); - - res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); - if (res == -1) - return (0); - - /* Parse the /ibm,dynamic-memory. - The first position gives the # of entries. The next two words - reflect the address of the memory block. The next four words are - the DRC index, reserved, list index and flags. - (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) - - #el Addr DRC-idx res list-idx flags - ------------------------------------------------- - | 4 | 8 | 4 | 4 | 4 | 4 |.... - ------------------------------------------------- - */ - - len = OF_getproplen(phandle, "ibm,dynamic-memory"); - if (len > 0) { - - /* We have to use a variable length array on the stack - since we have very limited stack space. - */ - cell_t arr[len/sizeof(cell_t)]; - - res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, - sizeof(arr)); - if (res == -1) - return (0); - - /* Number of elements */ - idx = arr[0]; - - /* First address. */ - dmem = (void*)&arr[1]; - - for (i = 0; i < idx; i++) { - base = *dmem; - dmem += 2; - flags = *dmem; - /* Use region only if available and not reserved. */ - if ((flags & 0x8) && !(flags & 0x80)) { - ofmem[lmsz].mr_start = base; - ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; - ofavail[lasz].mr_start = base; - ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; - lmsz++; - lasz++; - } - dmem++; - } - } - - *msz = lmsz; - *asz = lasz; - - return (1); -} /* * This is called during powerpc_init, before the system is really initialized. * It shall provide the total and the available regions of RAM. @@ -349,62 +256,31 @@ ofw_mem_regions(struct mem_region **memp, int *memsz, struct mem_region **availp, int *availsz) { phandle_t phandle; - vm_offset_t maxphysaddr; int asz, msz, fsz; - int i, j, res; + int i, j; int still_merging; - char name[31]; asz = msz = 0; /* - * Get memory from all the /memory nodes. + * Get memory. */ - for (phandle = OF_child(OF_peer(0)); phandle != 0; - phandle = OF_peer(phandle)) { - if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) - continue; - if (strncmp(name, "memory", sizeof(name)) != 0) - continue; + phandle = OF_finddevice("/memory"); + if (phandle == -1) + phandle = OF_finddevice("/memory@0"); - res = parse_ofw_memory(phandle, "reg", &OFmem[msz]); - msz += res/sizeof(struct mem_region); - if (OF_getproplen(phandle, "available") >= 0) - res = parse_ofw_memory(phandle, "available", - &OFavail[asz]); - else - res = parse_ofw_memory(phandle, "reg", &OFavail[asz]); - asz += res/sizeof(struct mem_region); - } - - /* Check for memory in ibm,dynamic-reconfiguration-memory */ - parse_drconf_memory(&msz, &asz, OFmem, OFavail); - - qsort(OFmem, msz, sizeof(*OFmem), mr_cmp); - qsort(OFavail, asz, sizeof(*OFavail), mr_cmp); + msz = parse_ofw_memory(phandle, "reg", OFmem); + nOFmem = msz / sizeof(struct mem_region); + asz = parse_ofw_memory(phandle, "available", OFavail); *memp = OFmem; - *memsz = msz; - - /* - * On some firmwares (SLOF), some memory may be marked available that - * doesn't actually exist. This manifests as an extension of the last - * available segment past the end of physical memory, so truncate that - * one. - */ - maxphysaddr = 0; - for (i = 0; i < msz; i++) - if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr) - maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size; - - if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr) - OFavail[asz - 1].mr_size = maxphysaddr - - OFavail[asz - 1].mr_start; - + *memsz = nOFmem; + /* * OFavail may have overlapping regions - collapse these * and copy out remaining regions to OFfree */ + asz /= sizeof(struct mem_region); do { still_merging = FALSE; for (i = 0; i < asz; i++) { @@ -593,7 +469,12 @@ openfirmware(void *args) int result; #ifdef SMP struct ofw_rv_args rv_args; + #endif + if (pmap_bootstrapped && ofw_real_mode) + args = (void *)pmap_kextract((vm_offset_t)args); + + #ifdef SMP rv_args.args = args; rv_args.in_progress = 1; smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, From 8fb6ad5d8ad692dba9805dee01b0c3e900bb97e4 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Thu, 2 Jun 2011 19:33:33 +0000 Subject: [PATCH 11/31] Fix the nfs related daemons so that they don't intermittently fail with "bind: address already in use". This problem was reported to the freebsd-stable@ mailing list on Feb. 19 under the subject heading "statd/lockd startup failure" by george+freebsd at m5p dot com. The problem is that the first combination of {udp,tcp X ipv4,ipv6} would select a port# dynamically, but one of the other three combinations would have that port# already in use. The patch is somewhat involved because it was requested by dougb@ that the four combinations use the same port# wherever possible. The patch splits the create_service() function into two functions. The first goes as far as bind(2) in a loop for up to GETPORT_MAXTRY - 1 times, attempting to use the same port# for all four cases. If these attempts fail, the last attempt allows the 4 cases to use different port #s. After this function has succeeded, the second function, called complete_service(), does the rest of what create_service() did. The three daemons mountd, rpc.lockd and rpc.statd all have a create_service() function that is patched in a similar way. However, create_service() has non-trivial differences for the three daemons that made it impractical to share the same functions between them. Reviewed by: jhb MFC after: 2 weeks --- usr.sbin/mountd/mountd.c | 243 ++++++++++++++++++++++++++++++++++----- 1 file changed, 213 insertions(+), 30 deletions(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 65bf44f4fcd..01a27eb0d08 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -158,6 +158,8 @@ struct fhreturn { int *fhr_secflavors; }; +#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ + /* Global defs */ char *add_expdir(struct dirlist **, char *, int); void add_dlist(struct dirlist **, struct dirlist *, @@ -167,7 +169,9 @@ int check_dirpath(char *); int check_options(struct dirlist *); int checkmask(struct sockaddr *sa); int chk_host(struct dirlist *, struct sockaddr *, int *, int *); -void create_service(struct netconfig *nconf); +static int create_service(struct netconfig *nconf); +static void complete_service(struct netconfig *nconf, char *port_str); +static void clearout_service(void); void del_mlist(char *hostp, char *dirp); struct dirlist *dirp_search(struct dirlist *, char *); int do_mount(struct exportlist *, struct grouplist *, int, @@ -233,6 +237,10 @@ int got_sighup = 0; int xcreated = 0; char *svcport_str = NULL; +static int mallocd_svcport = 0; +static int *sock_fd; +static int sock_fdcnt; +static int sock_fdpos; int opt_flags; static int have_v6 = 1; @@ -281,6 +289,8 @@ main(int argc, char **argv) in_port_t svcport; int c, k, s; int maxrec = RPC_MAXDATASIZE; + int attempt_cnt, port_len, port_pos, ret; + char **port_list; /* Check that another mountd isn't already running. */ pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); @@ -451,17 +461,97 @@ main(int argc, char **argv) hosts[nhosts - 1] = "127.0.0.1"; } + attempt_cnt = 1; + sock_fdcnt = 0; + sock_fd = NULL; + port_list = NULL; + port_len = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { if (nconf->nc_flag & NC_VISIBLE) { if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ + } else { + ret = create_service(nconf); + if (ret == 1) + /* Ignore this call */ + continue; + if (ret < 0) { + /* + * Failed to bind port, so close off + * all sockets created and try again + * if the port# was dynamically + * assigned via bind(2). + */ + clearout_service(); + if (mallocd_svcport != 0 && + attempt_cnt < GETPORT_MAXTRY) { + free(svcport_str); + svcport_str = NULL; + mallocd_svcport = 0; + } else { + errno = EADDRINUSE; + syslog(LOG_ERR, + "bindresvport_sa: %m"); + exit(1); + } + + /* Start over at the first service. */ + free(sock_fd); + sock_fdcnt = 0; + sock_fd = NULL; + nc_handle = setnetconfig(); + attempt_cnt++; + } else if (mallocd_svcport != 0 && + attempt_cnt == GETPORT_MAXTRY) { + /* + * For the last attempt, allow + * different port #s for each nconf + * by saving the svcport_str and + * setting it back to NULL. + */ + port_list = realloc(port_list, + (port_len + 1) * sizeof(char *)); + if (port_list == NULL) + out_of_mem(); + port_list[port_len++] = svcport_str; + svcport_str = NULL; + mallocd_svcport = 0; + } + } + } + } + + /* + * Successfully bound the ports, so call complete_service() to + * do the rest of the setup on the service(s). + */ + sock_fdpos = 0; + port_pos = 0; + nc_handle = setnetconfig(); + while ((nconf = getnetconfig(nc_handle))) { + if (nconf->nc_flag & NC_VISIBLE) { + if (have_v6 == 0 && strcmp(nconf->nc_protofmly, + "inet6") == 0) { + /* DO NOTHING */ + } else if (port_list != NULL) { + if (port_pos >= port_len) { + syslog(LOG_ERR, "too many port#s"); + exit(1); + } + complete_service(nconf, port_list[port_pos++]); } else - create_service(nconf); + complete_service(nconf, svcport_str); } } endnetconfig(nc_handle); + free(sock_fd); + if (port_list != NULL) { + for (port_pos = 0; port_pos < port_len; port_pos++) + free(port_list[port_pos]); + free(port_list); + } if (xcreated == 0) { syslog(LOG_ERR, "could not create any services"); @@ -491,30 +581,31 @@ main(int argc, char **argv) /* * This routine creates and binds sockets on the appropriate - * addresses. It gets called one time for each transport and - * registrates the service with rpcbind on that trasport. + * addresses. It gets called one time for each transport. + * It returns 0 upon success, 1 for ingore the call and -1 to indicate + * bind failed with EADDRINUSE. + * Any file descriptors that have been created are stored in sock_fd and + * the total count of them is maintained in sock_fdcnt. */ -void +static int create_service(struct netconfig *nconf) { struct addrinfo hints, *res = NULL; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct __rpc_sockinfo si; - struct netbuf servaddr; - SVCXPRT *transp = NULL; int aicode; int fd; int nhostsbak; int one = 1; int r; - int registered = 0; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ + int mallocd_res; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) - return; /* not my type */ + return (1); /* not my type */ /* * XXX - using RPC library internal functions. @@ -522,7 +613,7 @@ create_service(struct netconfig *nconf) if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); - return; + return (1); } /* Get mountd's address on this transport */ @@ -538,6 +629,12 @@ create_service(struct netconfig *nconf) nhostsbak = nhosts; while (nhostsbak > 0) { --nhostsbak; + sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); + if (sock_fd == NULL) + out_of_mem(); + sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ + mallocd_res = 0; + /* * XXX - using RPC library internal functions. */ @@ -549,14 +646,16 @@ create_service(struct netconfig *nconf) syslog(non_fatal ? LOG_DEBUG : LOG_ERR, "cannot create socket for %s", nconf->nc_netid); - return; + if (non_fatal != 0) + continue; + exit(1); } switch (hints.ai_family) { case AF_INET: if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET6 address. @@ -571,7 +670,7 @@ create_service(struct netconfig *nconf) case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET address. @@ -607,6 +706,7 @@ create_service(struct netconfig *nconf) res = malloc(sizeof(struct addrinfo)); if (res == NULL) out_of_mem(); + mallocd_res = 1; res->ai_flags = hints.ai_flags; res->ai_family = hints.ai_family; res->ai_protocol = hints.ai_protocol; @@ -620,7 +720,7 @@ create_service(struct netconfig *nconf) sin->sin_addr.s_addr = htonl(INADDR_ANY); res->ai_addr = (struct sockaddr*) sin; res->ai_addrlen = (socklen_t) - sizeof(res->ai_addr); + sizeof(struct sockaddr_in); break; case AF_INET6: sin6 = malloc(sizeof(struct sockaddr_in6)); @@ -631,10 +731,12 @@ create_service(struct netconfig *nconf) sin6->sin6_addr = in6addr_any; res->ai_addr = (struct sockaddr*) sin6; res->ai_addrlen = (socklen_t) - sizeof(res->ai_addr); - break; - default: + sizeof(struct sockaddr_in6); break; + default: + syslog(LOG_ERR, "bad addr fam %d", + res->ai_family); + exit(1); } } else { if ((aicode = getaddrinfo(NULL, svcport_str, @@ -643,6 +745,7 @@ create_service(struct netconfig *nconf) "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } @@ -652,16 +755,91 @@ create_service(struct netconfig *nconf) syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } + /* Store the fd. */ + sock_fd[sock_fdcnt - 1] = fd; + + /* Now, attempt the bind. */ r = bindresvport_sa(fd, res->ai_addr); if (r != 0) { + if (errno == EADDRINUSE && mallocd_svcport != 0) { + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + return (-1); + } syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } + if (svcport_str == NULL) { + svcport_str = malloc(NI_MAXSERV * sizeof(char)); + if (svcport_str == NULL) + out_of_mem(); + mallocd_svcport = 1; + + if (getnameinfo(res->ai_addr, + res->ai_addr->sa_len, NULL, NI_MAXHOST, + svcport_str, NI_MAXSERV * sizeof(char), + NI_NUMERICHOST | NI_NUMERICSERV)) + errx(1, "Cannot get port number"); + } + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + res = NULL; + } + return (0); +} + +/* + * Called after all the create_service() calls have succeeded, to complete + * the setup and registration. + */ +static void +complete_service(struct netconfig *nconf, char *port_str) +{ + struct addrinfo hints, *res = NULL; + struct __rpc_sockinfo si; + struct netbuf servaddr; + SVCXPRT *transp = NULL; + int aicode, fd, nhostsbak; + int registered = 0; + + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + return; /* not my type */ + + /* + * XXX - using RPC library internal functions. + */ + if (!__rpc_nconf2sockinfo(nconf, &si)) { + syslog(LOG_ERR, "cannot get information for %s", + nconf->nc_netid); + return; + } + + nhostsbak = nhosts; + while (nhostsbak > 0) { + --nhostsbak; + if (sock_fdpos >= sock_fdcnt) { + /* Should never happen. */ + syslog(LOG_ERR, "Ran out of socket fd's"); + return; + } + fd = sock_fd[sock_fdpos++]; + if (fd < 0) + continue; + if (nconf->nc_semantics != NC_TPI_CLTS) listen(fd, SOMAXCONN); @@ -696,19 +874,7 @@ create_service(struct netconfig *nconf) hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; - if (svcport_str == NULL) { - svcport_str = malloc(NI_MAXSERV * sizeof(char)); - if (svcport_str == NULL) - out_of_mem(); - - if (getnameinfo(res->ai_addr, - res->ai_addr->sa_len, NULL, NI_MAXHOST, - svcport_str, NI_MAXSERV * sizeof(char), - NI_NUMERICHOST | NI_NUMERICSERV)) - errx(1, "Cannot get port number"); - } - - if((aicode = getaddrinfo(NULL, svcport_str, &hints, + if ((aicode = getaddrinfo(NULL, port_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address: %s", gai_strerror(aicode)); @@ -728,6 +894,23 @@ create_service(struct netconfig *nconf) } /* end while */ } +/* + * Clear out sockets after a failure to bind one of them, so that the + * cycle of socket creation/binding can start anew. + */ +static void +clearout_service(void) +{ + int i; + + for (i = 0; i < sock_fdcnt; i++) { + if (sock_fd[i] >= 0) { + shutdown(sock_fd[i], SHUT_RDWR); + close(sock_fd[i]); + } + } +} + static void usage(void) { From 795b2dc06a84434b6d8528c9cd408f578d50d9fb Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Thu, 2 Jun 2011 19:49:47 +0000 Subject: [PATCH 12/31] Fix the nfs related daemons so that they don't intermittently fail with "bind: address already in use". This problem was reported to the freebsd-stable@ mailing list on Feb. 19 under the subject heading "statd/lockd startup failure" by george+freebsd at m5p dot com. The problem is that the first combination of {udp,tcp X ipv4,ipv6} would select a port# dynamically, but one of the other three combinations would have that port# already in use. The patch is somewhat involved because it was requested by dougb@ that the four combinations use the same port# wherever possible. The patch splits the create_service() function into two functions. The first goes as far as bind(2) in a loop for up to GETPORT_MAXTRY - 1 times, attempting to use the same port# for all four cases. If these attempts fail, the last attempt allows the 4 cases to use different port #s. After this function has succeeded, the second function, called complete_service(), does the rest of what create_service() did. The three daemons mountd, rpc.lockd and rpc.statd all have a create_service() function that is patched in a similar way. However, create_service() has non-trivial differences for the three daemons that made it impractical to share the same functions between them. Reviewed by: jhb MFC after: 2 weeks --- usr.sbin/rpc.lockd/lockd.c | 249 ++++++++++++++++++++++++++++++++----- 1 file changed, 221 insertions(+), 28 deletions(-) diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c index fb9e536e848..b3402ff20c1 100644 --- a/usr.sbin/rpc.lockd/lockd.c +++ b/usr.sbin/rpc.lockd/lockd.c @@ -74,6 +74,8 @@ __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); #include "lockd.h" #include +#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ + int debug_level = 0; /* 0 = no debugging syslog() calls */ int _rpcsvcdirty = 0; @@ -84,13 +86,19 @@ int kernel_lockd_client; pid_t client_pid; struct mon mon_host; char **hosts, *svcport_str = NULL; +static int mallocd_svcport = 0; +static int *sock_fd; +static int sock_fdcnt; +static int sock_fdpos; int nhosts = 0; int xcreated = 0; char **addrs; /* actually (netid, uaddr) pairs */ int naddrs; /* count of how many (netid, uaddr) pairs */ char localhost[] = "localhost"; -void create_service(struct netconfig *nconf); +static int create_service(struct netconfig *nconf); +static void complete_service(struct netconfig *nconf, char *port_str); +static void clearout_service(void); void lookup_addresses(struct netconfig *nconf); void init_nsm(void); void nlm_prog_0(struct svc_req *, SVCXPRT *); @@ -119,6 +127,8 @@ main(int argc, char **argv) int have_v6 = 1; int maxrec = RPC_MAXDATASIZE; in_port_t svcport = 0; + int attempt_cnt, port_len, port_pos, ret; + char **port_list; while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) { switch (ch) { @@ -309,6 +319,11 @@ main(int argc, char **argv) } endnetconfig(nc_handle); } else { + attempt_cnt = 1; + sock_fdcnt = 0; + sock_fd = NULL; + port_list = NULL; + port_len = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { /* We want to listen only on udp6, tcp6, udp, tcp transports */ @@ -317,11 +332,96 @@ main(int argc, char **argv) if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else { - create_service(nconf); + ret = create_service(nconf); + if (ret == 1) + /* Ignore this call */ + continue; + if (ret < 0) { + /* + * Failed to bind port, so close + * off all sockets created and + * try again if the port# was + * dynamically assigned via + * bind(2). + */ + clearout_service(); + if (mallocd_svcport != 0 && + attempt_cnt < + GETPORT_MAXTRY) { + free(svcport_str); + svcport_str = NULL; + mallocd_svcport = 0; + } else { + errno = EADDRINUSE; + syslog(LOG_ERR, + "bindresvport_sa: %m"); + exit(1); + } + + /* + * Start over at the first + * service. + */ + free(sock_fd); + sock_fdcnt = 0; + sock_fd = NULL; + nc_handle = setnetconfig(); + attempt_cnt++; + } else if (mallocd_svcport != 0 && + attempt_cnt == GETPORT_MAXTRY) { + /* + * For the last attempt, allow + * different port #s for each + * nconf by saving the + * svcport_str and setting it + * back to NULL. + */ + port_list = realloc(port_list, + (port_len + 1) * + sizeof(char *)); + if (port_list == NULL) + out_of_mem(); + port_list[port_len++] = + svcport_str; + svcport_str = NULL; + mallocd_svcport = 0; + } } } } + + /* + * Successfully bound the ports, so call complete_service() to + * do the rest of the setup on the service(s). + */ + sock_fdpos = 0; + port_pos = 0; + nc_handle = setnetconfig(); + while ((nconf = getnetconfig(nc_handle))) { + /* We want to listen only on udp6, tcp6, udp, tcp transports */ + if (nconf->nc_flag & NC_VISIBLE) { + /* Skip if there's no IPv6 support */ + if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { + /* DO NOTHING */ + } else if (port_list != NULL) { + if (port_pos >= port_len) { + syslog(LOG_ERR, + "too many port#s"); + exit(1); + } + complete_service(nconf, + port_list[port_pos++]); + } else + complete_service(nconf, svcport_str); + } + } endnetconfig(nc_handle); + free(sock_fd); + if (port_list != NULL) { + for (port_pos = 0; port_pos < port_len; port_pos++) + free(port_list[port_pos]); + free(port_list); + } } /* @@ -386,29 +486,30 @@ main(int argc, char **argv) /* * This routine creates and binds sockets on the appropriate - * addresses. It gets called one time for each transport and - * registrates the service with rpcbind on that trasport. + * addresses. It gets called one time for each transport. + * It returns 0 upon success, 1 for ingore the call and -1 to indicate + * bind failed with EADDRINUSE. + * Any file descriptors that have been created are stored in sock_fd and + * the total count of them is maintained in sock_fdcnt. */ -void +static int create_service(struct netconfig *nconf) { struct addrinfo hints, *res = NULL; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct __rpc_sockinfo si; - struct netbuf servaddr; - SVCXPRT *transp = NULL; int aicode; int fd; int nhostsbak; int r; - int registered = 0; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ + int mallocd_res; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) - return; /* not my type */ + return (1); /* not my type */ /* * XXX - using RPC library internal functions. @@ -416,7 +517,7 @@ create_service(struct netconfig *nconf) if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); - return; + return (1); } /* Get rpc.statd's address on this transport */ @@ -432,6 +533,11 @@ create_service(struct netconfig *nconf) nhostsbak = nhosts; while (nhostsbak > 0) { --nhostsbak; + sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); + if (sock_fd == NULL) + out_of_mem(); + sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ + mallocd_res = 0; /* * XXX - using RPC library internal functions. @@ -446,7 +552,7 @@ create_service(struct netconfig *nconf) case AF_INET: if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET6 address. @@ -461,7 +567,7 @@ create_service(struct netconfig *nconf) case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET address. @@ -485,6 +591,7 @@ create_service(struct netconfig *nconf) res = malloc(sizeof(struct addrinfo)); if (res == NULL) out_of_mem(); + mallocd_res = 1; res->ai_flags = hints.ai_flags; res->ai_family = hints.ai_family; res->ai_protocol = hints.ai_protocol; @@ -498,7 +605,7 @@ create_service(struct netconfig *nconf) sin->sin_addr.s_addr = htonl(INADDR_ANY); res->ai_addr = (struct sockaddr*) sin; res->ai_addrlen = (socklen_t) - sizeof(res->ai_addr); + sizeof(struct sockaddr_in); break; case AF_INET6: sin6 = malloc(sizeof(struct sockaddr_in6)); @@ -508,10 +615,14 @@ create_service(struct netconfig *nconf) sin6->sin6_port = htons(0); sin6->sin6_addr = in6addr_any; res->ai_addr = (struct sockaddr*) sin6; - res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); + res->ai_addrlen = (socklen_t) + sizeof(struct sockaddr_in6); break; default: - break; + syslog(LOG_ERR, + "bad addr fam %d", + res->ai_family); + exit(1); } } else { if ((aicode = getaddrinfo(NULL, svcport_str, @@ -520,6 +631,7 @@ create_service(struct netconfig *nconf) "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } @@ -529,16 +641,92 @@ create_service(struct netconfig *nconf) syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } + + /* Store the fd. */ + sock_fd[sock_fdcnt - 1] = fd; + + /* Now, attempt the bind. */ r = bindresvport_sa(fd, res->ai_addr); if (r != 0) { + if (errno == EADDRINUSE && mallocd_svcport != 0) { + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + return (-1); + } syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } + if (svcport_str == NULL) { + svcport_str = malloc(NI_MAXSERV * sizeof(char)); + if (svcport_str == NULL) + out_of_mem(); + mallocd_svcport = 1; + + if (getnameinfo(res->ai_addr, + res->ai_addr->sa_len, NULL, NI_MAXHOST, + svcport_str, NI_MAXSERV * sizeof(char), + NI_NUMERICHOST | NI_NUMERICSERV)) + errx(1, "Cannot get port number"); + } + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + res = NULL; + } + return (0); +} + +/* + * Called after all the create_service() calls have succeeded, to complete + * the setup and registration. + */ +static void +complete_service(struct netconfig *nconf, char *port_str) +{ + struct addrinfo hints, *res = NULL; + struct __rpc_sockinfo si; + struct netbuf servaddr; + SVCXPRT *transp = NULL; + int aicode, fd, nhostsbak; + int registered = 0; + + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + return; /* not my type */ + + /* + * XXX - using RPC library internal functions. + */ + if (!__rpc_nconf2sockinfo(nconf, &si)) { + syslog(LOG_ERR, "cannot get information for %s", + nconf->nc_netid); + return; + } + + nhostsbak = nhosts; + while (nhostsbak > 0) { + --nhostsbak; + if (sock_fdpos >= sock_fdcnt) { + /* Should never happen. */ + syslog(LOG_ERR, "Ran out of socket fd's"); + return; + } + fd = sock_fd[sock_fdpos++]; + if (fd < 0) + continue; + if (nconf->nc_semantics != NC_TPI_CLTS) listen(fd, SOMAXCONN); @@ -582,19 +770,7 @@ create_service(struct netconfig *nconf) hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; - if (svcport_str == NULL) { - svcport_str = malloc(NI_MAXSERV * sizeof(char)); - if (svcport_str == NULL) - out_of_mem(); - - if (getnameinfo(res->ai_addr, - res->ai_addr->sa_len, NULL, NI_MAXHOST, - svcport_str, NI_MAXSERV * sizeof(char), - NI_NUMERICHOST | NI_NUMERICSERV)) - errx(1, "Cannot get port number"); - } - - if((aicode = getaddrinfo(NULL, svcport_str, &hints, + if ((aicode = getaddrinfo(NULL, port_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address: %s", gai_strerror(aicode)); @@ -616,6 +792,23 @@ create_service(struct netconfig *nconf) } /* end while */ } +/* + * Clear out sockets after a failure to bind one of them, so that the + * cycle of socket creation/binding can start anew. + */ +static void +clearout_service(void) +{ + int i; + + for (i = 0; i < sock_fdcnt; i++) { + if (sock_fd[i] >= 0) { + shutdown(sock_fd[i], SHUT_RDWR); + close(sock_fd[i]); + } + } +} + /* * Look up addresses for the kernel to create transports for. */ From 6924e68e11d31cd378f101ebfa7d0a8f3784d3e6 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Thu, 2 Jun 2011 20:15:32 +0000 Subject: [PATCH 13/31] Fix the nfs related daemons so that they don't intermittently fail with "bind: address already in use". This problem was reported to the freebsd-stable@ mailing list on Feb. 19 under the subject heading "statd/lockd startup failure" by george+freebsd at m5p dot com. The problem is that the first combination of {udp,tcp X ipv4,ipv6} would select a port# dynamically, but one of the other three combinations would have that port# already in use. The patch is somewhat involved because it was requested by dougb@ that the four combinations use the same port# wherever possible. The patch splits the create_service() function into two functions. The first goes as far as bind(2) in a loop for up to GETPORT_MAXTRY - 1 times, attempting to use the same port# for all four cases. If these attempts fail, the last attempt allows the 4 cases to use different port #s. After this function has succeeded, the second function, called complete_service(), does the rest of what create_service() did. The three daemons mountd, rpc.lockd and rpc.statd all have a create_service() function that is patched in a similar way. However, create_service() has non-trivial differences for the three daemons that made it impractical to share the same functions between them. Reviewed by: jhb MFC after: 2 weeks --- usr.sbin/rpc.statd/statd.c | 238 ++++++++++++++++++++++++++++++++----- 1 file changed, 211 insertions(+), 27 deletions(-) diff --git a/usr.sbin/rpc.statd/statd.c b/usr.sbin/rpc.statd/statd.c index b8b4311c2bf..ff537f84b53 100644 --- a/usr.sbin/rpc.statd/statd.c +++ b/usr.sbin/rpc.statd/statd.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -55,13 +56,21 @@ __FBSDID("$FreeBSD$"); #include #include "statd.h" +#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ + int debug = 0; /* Controls syslog() calls for debug messages */ char **hosts, *svcport_str = NULL; int nhosts = 0; int xcreated = 0; +static int mallocd_svcport = 0; +static int *sock_fd; +static int sock_fdcnt; +static int sock_fdpos; -void create_service(struct netconfig *nconf); +static int create_service(struct netconfig *nconf); +static void complete_service(struct netconfig *nconf, char *port_str); +static void clearout_service(void); static void handle_sigchld(int sig); void out_of_mem(void); @@ -78,6 +87,8 @@ main(int argc, char **argv) char *endptr, **hosts_bak; int have_v6 = 1; int maxrec = RPC_MAXDATASIZE; + int attempt_cnt, port_len, port_pos, ret; + char **port_list; while ((ch = getopt(argc, argv, "dh:p:")) != -1) switch (ch) { @@ -176,6 +187,11 @@ main(int argc, char **argv) hosts[nhosts - 1] = "127.0.0.1"; } + attempt_cnt = 1; + sock_fdcnt = 0; + sock_fd = NULL; + port_list = NULL; + port_len = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { /* We want to listen only on udp6, tcp6, udp, tcp transports */ @@ -184,11 +200,87 @@ main(int argc, char **argv) if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else { - create_service(nconf); + ret = create_service(nconf); + if (ret == 1) + /* Ignore this call */ + continue; + if (ret < 0) { + /* + * Failed to bind port, so close off + * all sockets created and try again + * if the port# was dynamically + * assigned via bind(2). + */ + clearout_service(); + if (mallocd_svcport != 0 && + attempt_cnt < GETPORT_MAXTRY) { + free(svcport_str); + svcport_str = NULL; + mallocd_svcport = 0; + } else { + errno = EADDRINUSE; + syslog(LOG_ERR, + "bindresvport_sa: %m"); + exit(1); + } + + /* Start over at the first service. */ + free(sock_fd); + sock_fdcnt = 0; + sock_fd = NULL; + nc_handle = setnetconfig(); + attempt_cnt++; + } else if (mallocd_svcport != 0 && + attempt_cnt == GETPORT_MAXTRY) { + /* + * For the last attempt, allow + * different port #s for each nconf + * by saving the svcport_str and + * setting it back to NULL. + */ + port_list = realloc(port_list, + (port_len + 1) * sizeof(char *)); + if (port_list == NULL) + out_of_mem(); + port_list[port_len++] = svcport_str; + svcport_str = NULL; + mallocd_svcport = 0; + } } } } + + /* + * Successfully bound the ports, so call complete_service() to + * do the rest of the setup on the service(s). + */ + sock_fdpos = 0; + port_pos = 0; + nc_handle = setnetconfig(); + while ((nconf = getnetconfig(nc_handle))) { + /* We want to listen only on udp6, tcp6, udp, tcp transports */ + if (nconf->nc_flag & NC_VISIBLE) { + /* Skip if there's no IPv6 support */ + if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { + /* DO NOTHING */ + } else if (port_list != NULL) { + if (port_pos >= port_len) { + syslog(LOG_ERR, "too many port#s"); + exit(1); + } + complete_service(nconf, port_list[port_pos++]); + } else + complete_service(nconf, svcport_str); + } + } endnetconfig(nc_handle); + free(sock_fd); + if (port_list != NULL) { + for (port_pos = 0; port_pos < port_len; port_pos++) + free(port_list[port_pos]); + free(port_list); + } + init_file("/var/db/statd.status"); /* Note that it is NOT sensible to run this program from inetd - the */ @@ -215,29 +307,30 @@ main(int argc, char **argv) /* * This routine creates and binds sockets on the appropriate - * addresses. It gets called one time for each transport and - * registrates the service with rpcbind on that trasport. + * addresses. It gets called one time for each transport. + * It returns 0 upon success, 1 for ingore the call and -1 to indicate + * bind failed with EADDRINUSE. + * Any file descriptors that have been created are stored in sock_fd and + * the total count of them is maintained in sock_fdcnt. */ -void +static int create_service(struct netconfig *nconf) { struct addrinfo hints, *res = NULL; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct __rpc_sockinfo si; - struct netbuf servaddr; - SVCXPRT *transp = NULL; int aicode; int fd; int nhostsbak; int r; - int registered = 0; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ + int mallocd_res; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) - return; /* not my type */ + return (1); /* not my type */ /* * XXX - using RPC library internal functions. @@ -245,7 +338,7 @@ create_service(struct netconfig *nconf) if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); - return; + return (1); } /* Get rpc.statd's address on this transport */ @@ -261,6 +354,11 @@ create_service(struct netconfig *nconf) nhostsbak = nhosts; while (nhostsbak > 0) { --nhostsbak; + sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); + if (sock_fd == NULL) + out_of_mem(); + sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ + mallocd_res = 0; /* * XXX - using RPC library internal functions. @@ -274,7 +372,7 @@ create_service(struct netconfig *nconf) case AF_INET: if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET6 address. @@ -289,7 +387,7 @@ create_service(struct netconfig *nconf) case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { - hints.ai_flags &= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET address. @@ -313,6 +411,7 @@ create_service(struct netconfig *nconf) res = malloc(sizeof(struct addrinfo)); if (res == NULL) out_of_mem(); + mallocd_res = 1; res->ai_flags = hints.ai_flags; res->ai_family = hints.ai_family; res->ai_protocol = hints.ai_protocol; @@ -326,7 +425,7 @@ create_service(struct netconfig *nconf) sin->sin_addr.s_addr = htonl(INADDR_ANY); res->ai_addr = (struct sockaddr*) sin; res->ai_addrlen = (socklen_t) - sizeof(res->ai_addr); + sizeof(struct sockaddr_in); break; case AF_INET6: sin6 = malloc(sizeof(struct sockaddr_in6)); @@ -336,10 +435,13 @@ create_service(struct netconfig *nconf) sin6->sin6_port = htons(0); sin6->sin6_addr = in6addr_any; res->ai_addr = (struct sockaddr*) sin6; - res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); + res->ai_addrlen = (socklen_t) + sizeof(struct sockaddr_in6); break; default: - break; + syslog(LOG_ERR, "bad addr fam %d", + res->ai_family); + exit(1); } } else { if ((aicode = getaddrinfo(NULL, svcport_str, @@ -348,6 +450,7 @@ create_service(struct netconfig *nconf) "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } @@ -357,16 +460,91 @@ create_service(struct netconfig *nconf) syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); + close(fd); continue; } } + /* Store the fd. */ + sock_fd[sock_fdcnt - 1] = fd; + + /* Now, attempt the bind. */ r = bindresvport_sa(fd, res->ai_addr); if (r != 0) { + if (errno == EADDRINUSE && mallocd_svcport != 0) { + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + return (-1); + } syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } + if (svcport_str == NULL) { + svcport_str = malloc(NI_MAXSERV * sizeof(char)); + if (svcport_str == NULL) + out_of_mem(); + mallocd_svcport = 1; + + if (getnameinfo(res->ai_addr, + res->ai_addr->sa_len, NULL, NI_MAXHOST, + svcport_str, NI_MAXSERV * sizeof(char), + NI_NUMERICHOST | NI_NUMERICSERV)) + errx(1, "Cannot get port number"); + } + if (mallocd_res != 0) { + free(res->ai_addr); + free(res); + } else + freeaddrinfo(res); + res = NULL; + } + return (0); +} + +/* + * Called after all the create_service() calls have succeeded, to complete + * the setup and registration. + */ +static void +complete_service(struct netconfig *nconf, char *port_str) +{ + struct addrinfo hints, *res = NULL; + struct __rpc_sockinfo si; + struct netbuf servaddr; + SVCXPRT *transp = NULL; + int aicode, fd, nhostsbak; + int registered = 0; + + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + return; /* not my type */ + + /* + * XXX - using RPC library internal functions. + */ + if (!__rpc_nconf2sockinfo(nconf, &si)) { + syslog(LOG_ERR, "cannot get information for %s", + nconf->nc_netid); + return; + } + + nhostsbak = nhosts; + while (nhostsbak > 0) { + --nhostsbak; + if (sock_fdpos >= sock_fdcnt) { + /* Should never happen. */ + syslog(LOG_ERR, "Ran out of socket fd's"); + return; + } + fd = sock_fd[sock_fdpos++]; + if (fd < 0) + continue; + if (nconf->nc_semantics != NC_TPI_CLTS) listen(fd, SOMAXCONN); @@ -397,19 +575,8 @@ create_service(struct netconfig *nconf) hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; - if (svcport_str == NULL) { - svcport_str = malloc(NI_MAXSERV * sizeof(char)); - if (svcport_str == NULL) - out_of_mem(); - if (getnameinfo(res->ai_addr, - res->ai_addr->sa_len, NULL, NI_MAXHOST, - svcport_str, NI_MAXSERV * sizeof(char), - NI_NUMERICHOST | NI_NUMERICSERV)) - errx(1, "Cannot get port number"); - } - - if((aicode = getaddrinfo(NULL, svcport_str, &hints, + if ((aicode = getaddrinfo(NULL, port_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address: %s", gai_strerror(aicode)); @@ -428,6 +595,23 @@ create_service(struct netconfig *nconf) } /* end while */ } +/* + * Clear out sockets after a failure to bind one of them, so that the + * cycle of socket creation/binding can start anew. + */ +static void +clearout_service(void) +{ + int i; + + for (i = 0; i < sock_fdcnt; i++) { + if (sock_fd[i] >= 0) { + shutdown(sock_fd[i], SHUT_RDWR); + close(sock_fd[i]); + } + } +} + static void usage() { From 37ddbd16a5a8978fd77f4a468ac913ada9299680 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 2 Jun 2011 20:56:42 +0000 Subject: [PATCH 14/31] When possible, join ranges of subsequest BIO_DELETE requests to handle more (up to 2048 instead of 256 or even 64) of them with single TRIM request. OCZ Vertex2/Vertex3 SSDs can handle no more then 64 ranges per TRIM request. Due to lack of BIO_DELETE clustering now, it means that we could delete no more then 2MB per request (on FS with 32K block) with limited request rate. This change increases delete rate on Vertex2 from 250MB/s to 950MB/s. --- sys/cam/ata/ata_da.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index 7418e1e9a22..f918956b042 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -115,10 +115,11 @@ struct disk_params { }; #define TRIM_MAX_BLOCKS 4 -#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64 +#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) +#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 8) struct trim_request { uint8_t data[TRIM_MAX_RANGES * 8]; - struct bio *bps[TRIM_MAX_RANGES]; + struct bio *bps[TRIM_MAX_BIOS]; }; struct ada_softc { @@ -1067,7 +1068,8 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) (bp = bioq_first(&softc->trim_queue)) != 0) { struct trim_request *req = &softc->trim_req; struct bio *bp1; - int bps = 0, ranges = 0; + uint64_t lastlba = (uint64_t)-1; + int bps = 0, c, lastcount = 0, off, ranges = 0; softc->trim_running = 1; bzero(req, sizeof(*req)); @@ -1078,10 +1080,22 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) softc->params.secsize; bioq_remove(&softc->trim_queue, bp1); - while (count > 0) { - int c = min(count, 0xffff); - int off = ranges * 8; + /* Try to extend the previous range. */ + if (lba == lastlba) { + c = min(count, 0xffff - lastcount); + lastcount += c; + off = (ranges - 1) * 8; + req->data[off + 6] = lastcount & 0xff; + req->data[off + 7] = + (lastcount >> 8) & 0xff; + count -= c; + lba += c; + } + + while (count > 0) { + c = min(count, 0xffff); + off = ranges * 8; req->data[off + 0] = lba & 0xff; req->data[off + 1] = (lba >> 8) & 0xff; req->data[off + 2] = (lba >> 16) & 0xff; @@ -1092,11 +1106,14 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) req->data[off + 7] = (c >> 8) & 0xff; lba += c; count -= c; + lastcount = c; ranges++; } + lastlba = lba; req->bps[bps++] = bp1; bp1 = bioq_first(&softc->trim_queue); - if (bp1 == NULL || + if (bps >= TRIM_MAX_BIOS || + bp1 == NULL || bp1->bio_bcount / softc->params.secsize > (softc->trim_max_ranges - ranges) * 0xffff) break; @@ -1370,8 +1387,7 @@ adadone(struct cam_periph *periph, union ccb *done_ccb) (struct trim_request *)ataio->data_ptr; int i; - for (i = 1; i < softc->trim_max_ranges && - req->bps[i]; i++) { + for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { struct bio *bp1 = req->bps[i]; bp1->bio_resid = bp->bio_resid; From a6c21ef2d1778055a5f0361ab75156cb3c8a58fc Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Thu, 2 Jun 2011 21:59:21 +0000 Subject: [PATCH 15/31] Use stripesize and stripeoffset in the automatic calculation of partition offsets. If user requests specific alignment and provider's stripesize is not zero, then use a least common multiple from the stripesize and user specified value. Also fix "gpart resize" implementation: do not try to align the partition size, because the start offset may be not aligned. Instead align the end offset and then calculate size. Also use stripesize and stripeoffset for "gpart resize" command. --- sbin/geom/class/part/geom_part.c | 51 +++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index 93b28ac8c9c..a433a0fcdad 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -306,7 +306,7 @@ gpart_autofill_resize(struct gctl_req *req) struct ggeom *gp; struct gprovider *pp; off_t last, size, start, new_size; - off_t lba, new_lba, alignment; + off_t lba, new_lba, alignment, offset; const char *s; int error, idx; @@ -341,6 +341,9 @@ gpart_autofill_resize(struct gctl_req *req) errc(EXIT_FAILURE, error, "Invalid alignment param"); if (alignment == 0) errx(EXIT_FAILURE, "Invalid alignment param"); + lba = pp->lg_stripesize / pp->lg_sectorsize; + if (lba % alignment) + alignment = g_lcm(lba, alignment); } error = gctl_delete_param(req, "alignment"); if (error) @@ -356,12 +359,10 @@ gpart_autofill_resize(struct gctl_req *req) /* no autofill necessary. */ if (alignment == 1) goto done; - if (new_size > alignment) - new_size = ALIGNDOWN(new_size, alignment); } + offset = pp->lg_stripeoffset / pp->lg_sectorsize; last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); - last = ALIGNDOWN(last, alignment); LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { s = find_provcfg(pp, "index"); if (s == NULL) @@ -375,24 +376,32 @@ gpart_autofill_resize(struct gctl_req *req) s = find_provcfg(pp, "start"); start = (off_t)strtoimax(s, NULL, 0); s = find_provcfg(pp, "end"); - lba = (off_t)strtoimax(s, NULL, 0) + 1; + lba = (off_t)strtoimax(s, NULL, 0); + size = lba - start + 1; - if (lba > last) { - geom_deletetree(&mesh); - return (ENOSPC); + if (new_size > 0 && new_size <= size) { + /* The start offset may be not aligned, so we align the end + * offset and then calculate the size. + */ + new_size = ALIGNDOWN(start + offset + new_size, + alignment) - start - offset; + goto done; } - size = lba - start; - pp = find_provider(gp, lba); - if (pp == NULL) - new_size = ALIGNDOWN(last - start + 1, alignment); - else { + + pp = find_provider(gp, lba + 1); + if (pp == NULL) { + new_size = ALIGNDOWN(last + offset + 1, alignment) - + start - offset; + if (new_size < size) + return (ENOSPC); + } else { s = find_provcfg(pp, "start"); new_lba = (off_t)strtoimax(s, NULL, 0); /* * Is there any free space between current and * next providers? */ - new_lba = ALIGNUP(new_lba, alignment); + new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset; if (new_lba > lba) new_size = new_lba - start; else { @@ -482,10 +491,16 @@ gpart_autofill(struct gctl_req *req) if (has_size && has_start && !has_alignment) goto done; - /* Adjust parameters to offset value for better alignment */ - s = find_provcfg(pp, "offset"); - offset = (s == NULL) ? 0: - (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; + /* + * If stripesize is not zero, then recalculate alignment value. + * Use LCM from stripesize and user specified alignment. + */ + len = pp->lg_stripesize / pp->lg_sectorsize; + if (len % alignment) + alignment = g_lcm(len, alignment); + + /* Adjust parameters to stripeoffset */ + offset = pp->lg_stripeoffset / pp->lg_sectorsize; start = ALIGNUP(start + offset, alignment); if (size + offset > alignment) size = ALIGNDOWN(size + offset, alignment); From 57512b16ae6413fc30f37f90cc5422f2cbd86529 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Thu, 2 Jun 2011 22:15:19 +0000 Subject: [PATCH 16/31] Always use LCM when stripesize > 0. --- sbin/geom/class/part/geom_part.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index a433a0fcdad..ae9f4b7b451 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -342,7 +342,7 @@ gpart_autofill_resize(struct gctl_req *req) if (alignment == 0) errx(EXIT_FAILURE, "Invalid alignment param"); lba = pp->lg_stripesize / pp->lg_sectorsize; - if (lba % alignment) + if (lba > 0) alignment = g_lcm(lba, alignment); } error = gctl_delete_param(req, "alignment"); @@ -496,7 +496,7 @@ gpart_autofill(struct gctl_req *req) * Use LCM from stripesize and user specified alignment. */ len = pp->lg_stripesize / pp->lg_sectorsize; - if (len % alignment) + if (len > 0 ) alignment = g_lcm(len, alignment); /* Adjust parameters to stripeoffset */ From cd507188bc717a9316166e9d8c143601a063554b Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Fri, 3 Jun 2011 00:11:13 +0000 Subject: [PATCH 17/31] Quantities stored on the stack on ppc64 tend to be twice as large as on ppc32, so make the early stack correspondingly twice as big. --- sys/powerpc/aim/locore64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index e71594e0c67..c200b4c2a15 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -75,7 +75,7 @@ .globl kernbase .set kernbase, KERNBASE -#define TMPSTKSZ 8192 /* 8K temporary stack */ +#define TMPSTKSZ 16384 /* 16K temporary stack */ /* * Globals From a00944499f3a4b4bb675820d367a7eee24a04b5b Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 05:16:33 +0000 Subject: [PATCH 18/31] Added support for the MANWIDTH environment variable: If set to a numeric value, used as the width manpages should be displayed. Otherwise, if set to a special value ``tty'', and output is to a terminal, the pages may be displayed over the whole width of the screen. --- usr.bin/man/man.1 | 8 +++++++- usr.bin/man/man.sh | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 index 58f43e5864e..133d5369908 100644 --- a/usr.bin/man/man.1 +++ b/usr.bin/man/man.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 1, 2010 +.Dd June 2, 2011 .Dt MAN 1 .Os .Sh NAME @@ -283,6 +283,12 @@ Restricts manual sections searched to the specified colon delimited list. Corresponds to the .Fl S option. +.It Ev MANWIDTH +If set to a numeric value, used as the width manpages should be displayed. +Otherwise, if set to a special value +.Dq Li tty , +and output is to a terminal, +the pages may be displayed over the whole width of the screen. .It Ev PAGER Program used to display files. If unset, diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh index 762970d076b..972f872d302 100755 --- a/usr.bin/man/man.sh +++ b/usr.bin/man/man.sh @@ -112,7 +112,11 @@ check_man() { setup_cattool $manpage decho " Found manpage $manpage" - if exists "$2" && is_newer $found $manpage; then + if [ -n "${use_width}" ]; then + # non-standard width + unset use_cat + decho " Skipping catpage: non-standard page width" + elif exists "$2" && is_newer $found $manpage; then # cat page found and is newer, use that use_cat=yes catpage=$found @@ -352,6 +356,10 @@ man_display_page() { ;; esac + if [ -n "${use_width}" ]; then + NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" + fi + if [ -n "$MANROFFSEQ" ]; then set -- -$MANROFFSEQ while getopts 'egprtv' preproc_arg; do @@ -562,6 +570,35 @@ man_setup() { build_manpath man_setup_locale + man_setup_width +} + +# Usage: man_setup_width +# Set up page width. +man_setup_width() { + local sizes + + unset use_width + case "$MANWIDTH" in + [0-9]*) + if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then + use_width=$MANWIDTH + fi + ;; + [Tt][Tt][Yy]) + if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then + set -- $sizes + if [ $2 -gt 80 ]; then + use_width=$(($2-2)) + fi + fi + ;; + esac + if [ -n "$use_width" ]; then + decho "Using non-standard page width: ${use_width}" + else + decho 'Using standard page width' + fi } # Usage: man_setup_locale @@ -900,6 +937,7 @@ VGRIND=vgrind COL=/usr/bin/col LOCALE=/usr/bin/locale +STTY=/bin/stty SYSCTL=/sbin/sysctl debug=0 From 1030a67f5b83d8810862a8ea2c59f728a300a976 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 05:16:54 +0000 Subject: [PATCH 19/31] Typo. --- usr.bin/man/man.conf.5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.bin/man/man.conf.5 b/usr.bin/man/man.conf.5 index 6326bc1ebf1..fdbd69e05b7 100644 --- a/usr.bin/man/man.conf.5 +++ b/usr.bin/man/man.conf.5 @@ -112,7 +112,7 @@ with the following contents: .Bd -literal -offset indent # Setup Japanese toolset MANLOCALE ja_JP.eucJP -EQN_JA /usr/local/bin/gepn +EQN_JA /usr/local/bin/geqn PIC_JA /usr/local/bin/gpic TBL_JA /usr/local/bin/gtbl NROFF_JA /usr/local/bin/groff -man -dlang=ja_JP.eucJP From a1528c80a53cb2796e8d1dd8edd461b08fe70320 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 05:56:52 +0000 Subject: [PATCH 20/31] Trim more when parsing MANCONFIG directive. --- usr.bin/man/man.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh index 972f872d302..5905dc2abe0 100755 --- a/usr.bin/man/man.sh +++ b/usr.bin/man/man.sh @@ -704,7 +704,7 @@ parse_file() { manlocales="$manlocales:$tstr" ;; MANCONFIG*) decho " MANCONFIG" 3 - trim "${line#MANCONF}" + trim "${line#MANCONFIG}" config_local="$tstr" ;; # Set variables in the form of FOO_BAR From 38c64884ffe46b9dbf3d9e29d835ec9e3ef380d2 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Fri, 3 Jun 2011 06:58:24 +0000 Subject: [PATCH 21/31] Add diagnostic message about not aligned partitions. Idea from: ivoras --- sys/geom/part/g_part.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index a3f857599f4..f24e7b54bda 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -248,6 +248,7 @@ g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp) { struct g_part_entry *e1, *e2; struct g_provider *pp; + off_t offset; int failed; failed = 0; @@ -294,6 +295,16 @@ g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp) (intmax_t)table->gpt_last); failed++; } + if (pp->stripesize > 0) { + offset = e1->gpe_start * pp->sectorsize; + if (e1->gpe_offset > offset) + offset = e1->gpe_offset; + if ((offset + pp->stripeoffset) % pp->stripesize) { + DPRINTF("partition %d is not aligned on %u " + "bytes\n", e1->gpe_index, pp->stripesize); + /* Don't treat this as a critical failure */ + } + } e2 = e1; while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) { if (e2->gpe_deleted || e2->gpe_internal) @@ -723,7 +734,11 @@ g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { sb = sbuf_new_auto(); G_PART_FULLNAME(table, entry, sb, gp->name); - sbuf_cat(sb, " added\n"); + if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0) + sbuf_printf(sb, " added, but partition is not " + "aligned on %u bytes\n", pp->stripesize); + else + sbuf_cat(sb, " added\n"); sbuf_finish(sb); gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); From 1524677adffebf689e175c58755b38fe8aa89a70 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 3 Jun 2011 07:25:36 +0000 Subject: [PATCH 22/31] Increase maximum supported number of ranges per TRIM command from 256 to 512 to use full potential of Intel X25-M SSDs. On synthetic test with 32K ranges it gives about 20% speedup, which probably costs more then 2K of RAM. --- sys/cam/ata/ata_da.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index f918956b042..8e933022390 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -114,9 +114,9 @@ struct disk_params { u_int64_t sectors; /* Total number sectors */ }; -#define TRIM_MAX_BLOCKS 4 +#define TRIM_MAX_BLOCKS 8 #define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) -#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 8) +#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) struct trim_request { uint8_t data[TRIM_MAX_RANGES * 8]; struct bio *bps[TRIM_MAX_BIOS]; From 04d172db03cae66daa04a1ec1c835d43de1b8130 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Fri, 3 Jun 2011 07:27:53 +0000 Subject: [PATCH 23/31] Bring over the relevant registers to use when implementing the quiet time portion of 802.11h. The AR5212 code has been brought over as a reference, it's currently untested. Obtained from: Atheros --- sys/dev/ath/ath_hal/ah.h | 13 ++++++++++ sys/dev/ath/ath_hal/ar5212/ar5212.h | 2 ++ sys/dev/ath/ath_hal/ar5212/ar5212_attach.c | 1 + sys/dev/ath/ath_hal/ar5212/ar5212_misc.c | 14 +++++++++++ sys/dev/ath/ath_hal/ar5212/ar5212reg.h | 1 + sys/dev/ath/ath_hal/ar5416/ar5416.h | 2 ++ sys/dev/ath/ath_hal/ar5416/ar5416_attach.c | 1 + sys/dev/ath/ath_hal/ar5416/ar5416_misc.c | 29 ++++++++++++++++++++++ 8 files changed, 63 insertions(+) diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index bbea10a7899..165d919d03d 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -735,6 +735,16 @@ typedef struct { #define HAL_PHYERR_PARAM_ENABLE 0x8000 /* Enable/Disable if applicable */ +/* + * Flag for setting QUIET period + */ +typedef enum { + HAL_QUIET_DISABLE = 0x0, + HAL_QUIET_ENABLE = 0x1, + HAL_QUIET_ADD_CURRENT_TSF = 0x2, /* add current TSF to next_start offset */ + HAL_QUIET_ADD_SWBA_RESP_TIME = 0x4, /* add beacon response time to next_start offset */ +} HAL_QUIET_FLAG; + /* * Hardware Access Layer (HAL) API. * @@ -909,6 +919,9 @@ struct ath_hal { u_int __ahdecl(*ah_getCTSTimeout)(struct ath_hal*); HAL_BOOL __ahdecl(*ah_setDecompMask)(struct ath_hal*, uint16_t, int); void __ahdecl(*ah_setCoverageClass)(struct ath_hal*, uint8_t, int); + HAL_STATUS __ahdecl(*ah_setQuiet)(struct ath_hal *ah, uint32_t period, + uint32_t duration, uint32_t nextStart, + HAL_QUIET_FLAG flag); /* DFS functions */ void __ahdecl(*ah_enableDfs)(struct ath_hal *ah, diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h index a9ea4efff64..16394a396f1 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h @@ -506,6 +506,8 @@ extern HAL_BOOL ar5212SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, extern HAL_BOOL ar5212GetDiagState(struct ath_hal *ah, int request, const void *args, uint32_t argsize, void **result, uint32_t *resultsize); +extern HAL_STATUS ar5212SetQuiet(struct ath_hal *ah, uint32_t period, + uint32_t duration, uint32_t nextStart, HAL_QUIET_FLAG flag); extern HAL_BOOL ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip); diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index 90605cf9fe5..5999a603f9c 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -127,6 +127,7 @@ static const struct ath_hal_private ar5212hal = {{ .ah_getCTSTimeout = ar5212GetCTSTimeout, .ah_setDecompMask = ar5212SetDecompMask, .ah_setCoverageClass = ar5212SetCoverageClass, + .ah_setQuiet = ar5212SetQuiet, /* DFS Functions */ .ah_enableDfs = ar5212EnableDfs, diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c index ad1b7ebaef3..276671d6db3 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c @@ -634,6 +634,20 @@ ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) } } +HAL_STATUS +ar5212SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, + uint32_t nextStart, HAL_QUIET_FLAG flag) +{ + OS_REG_WRITE(ah, AR_QUIET2, period | (duration << AR_QUIET2_QUIET_DUR_S)); + if (flag & HAL_QUIET_ENABLE) { + OS_REG_WRITE(ah, AR_QUIET1, nextStart | (1 << 16)); + } + else { + OS_REG_WRITE(ah, AR_QUIET1, nextStart); + } + return HAL_OK; +} + void ar5212SetPCUConfig(struct ath_hal *ah) { diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212reg.h b/sys/dev/ath/ath_hal/ar5212/ar5212reg.h index f99b203e95f..15c1a58f7df 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212reg.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212reg.h @@ -300,6 +300,7 @@ #define AR_QUIET1_NEXT_QUIET 0xffff #define AR_QUIET1_QUIET_ENABLE 0x10000 /* Enable Quiet time operation */ #define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x20000 /* Do we ack/cts during quiet period */ +#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17 #define AR_QUIET2 0x8100 /* More Quiet time programming */ #define AR_QUIET2_QUIET_PER_S 0 /* Periodicity of quiet period (TU) */ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h index 984b5e8d504..510afe0436e 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h @@ -194,6 +194,8 @@ extern uint32_t ar5416Get11nExtBusy(struct ath_hal *ah); extern void ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode); extern HAL_HT_RXCLEAR ar5416Get11nRxClear(struct ath_hal *ah); extern void ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear); +extern HAL_STATUS ar5416SetQuiet(struct ath_hal *ah, uint32_t period, + uint32_t duration, uint32_t nextStart, HAL_QUIET_FLAG flag); extern HAL_STATUS ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result); extern HAL_BOOL ar5416GetDiagState(struct ath_hal *ah, int request, diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index aa9d97b227a..22d05ff80ce 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -139,6 +139,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; ah->ah_setDecompMask = ar5416SetDecompMask; ah->ah_setCoverageClass = ar5416SetCoverageClass; + ah->ah_setQuiet = ar5416SetQuiet; ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry; ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c index 4b1ba220ad7..2c08730bbe9 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c @@ -273,6 +273,35 @@ ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) } } +/* XXX shouldn't be here! */ +#define TU_TO_USEC(_tu) ((_tu) << 10) + +HAL_STATUS +ar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, + uint32_t nextStart, HAL_QUIET_FLAG flag) +{ + uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */ + uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */ + if (flag & HAL_QUIET_ENABLE) { + if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) { + /* Add the nextStart offset to the current TSF */ + nextStart_us += OS_REG_READ(ah, AR_TSF_L32); + } + if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) { + nextStart_us += ath_hal_sw_beacon_response_time; + } + OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); + OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR)); + OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us); + OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); + } else { + OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); + } + return HAL_OK; +} +#undef TU_TO_USEC + HAL_STATUS ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result) From 8bf9aaabf988911e85e6ca6ab0cae09a6599c588 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 10:39:36 +0000 Subject: [PATCH 24/31] Generally clean up markup. --- sbin/geom/class/part/gpart.8 | 156 +++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 71 deletions(-) diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8 index e4f6cc6e840..940620c9b5a 100644 --- a/sbin/geom/class/part/gpart.8 +++ b/sbin/geom/class/part/gpart.8 @@ -61,7 +61,8 @@ which is used to define a logical partition. The .Dv GEOM_PART_EBR_COMPAT option enables backward compatibility for partition names -in the EBR scheme. Also it makes impossible any types of actions +in the EBR scheme. +Also it makes impossible any types of actions with such partitions. The .Dv GEOM_PART_GPT @@ -170,7 +171,7 @@ utility: .\" ==== SHOW ==== .Nm .Cm show -.Op Fl l | Fl r +.Op Fl l | r .Op Fl p .Op Ar geom ... .\" ==== UNDO ==== @@ -200,11 +201,14 @@ The partition begins on the logical block address given by the option. Its size is given by the .Fl s Ar size -option. SI unit suffixes are allowed. One or both +option. +SI unit suffixes are allowed. +One or both .Fl b and .Fl s -options can be omitted. If so they are automatically calculated. +options can be omitted. +If so they are automatically calculated. The type of the partition is given by the .Fl t Ar type option. @@ -399,7 +403,7 @@ about its use. Recover corrupt partition's scheme metadata on the geom .Ar geom . See the section entitled -.Sx "RECOVERING" +.Sx RECOVERING below for the additional information. .Pp Additional options include: @@ -453,7 +457,7 @@ action and given from standard input. Only partition table may be restored. This action does not affect content of partitions. This mean that you should copy your data from backup after restoring -partition table and write bootcode again if it is needed. +partition table and write bootcode again if it is needed. .Pp Additional options include: .Bl -tag -width 10n @@ -474,7 +478,7 @@ about its use. .It Cm set Set the named attribute on the partition entry. See the section entitled -.Sx "ATTRIBUTES" +.Sx ATTRIBUTES below for a list of available attributes. .Pp Additional options include: @@ -511,7 +515,7 @@ action and can be used to undo any changes that have not been committed. .It Cm unset Clear the named attribute on the partition entry. See the section entitled -.Sx "ATTRIBUTES" +.Sx ATTRIBUTES below for a list of available attributes. .Pp Additional options include: @@ -616,75 +620,75 @@ by GPT. .El .Sh ATTRIBUTES The scheme-specific attributes for EBR: -.Bl -tag -width ".Ar active" -.It Ar active +.Bl -tag -width ".Cm active" +.It Cm active .El .Pp The scheme-specific attributes for GPT: -.Bl -tag -width ".Ar bootfailed" -.It Ar bootme +.Bl -tag -width ".Cm bootfailed" +.It Cm bootme When set, the .Nm gptboot stage 1 boot loader will try to boot the system from this partition. Multiple partitions might be marked with the -.Ar bootme +.Cm bootme attribute. In such scenario the .Nm gptboot will try all -.Ar bootme +.Cm bootme partitions one by one, until the next boot stage is successfully entered. -.It Ar bootonce +.It Cm bootonce Setting this attribute automatically sets the -.Ar bootme +.Cm bootme attribute. When set, the .Nm gptboot stage 1 boot loader will try to boot the system from this partition only once. Partitions with both -.Ar bootonce +.Cm bootonce and -.Ar bootme +.Cm bootme attributes are tried before partitions with only the -.Ar bootme +.Cm bootme attribute. Before -.Ar bootonce +.Cm bootonce partition is tried, the .Nm gptboot removes the -.Ar bootme +.Cm bootme attribute and tries to execute the next boot stage. If it fails, the -.Ar bootonce +.Cm bootonce attribute that is now alone is replaced with the -.Ar bootfailed +.Cm bootfailed attribute. If the execution of the next boot stage succeeds, but the system is not fully booted, the .Nm gptboot will look for -.Ar bootonce +.Cm bootonce attributes alone (without the -.Ar bootme +.Cm bootme attribute) on the next system boot and will replace those with the -.Ar bootfailed +.Cm bootfailed attribute. If the system is fully booted, the .Pa /etc/rc.d/gptboot start-up script will look for partition with the -.Ar bootonce +.Cm bootonce attribute alone, will remove the attribute and log that the system was successfully booted from this partition. There should be at most one -.Ar bootonce +.Cm bootonce partition when system is successfully booted. Multiple partitions might be marked with the -.Ar bootonce +.Cm bootonce and -.Ar bootme +.Cm bootme attribute pairs. -.It Ar bootfailed +.It Cm bootfailed This attribute should not be manually managed. It is managed by the .Nm gptboot @@ -692,24 +696,24 @@ stage 1 boot loader and the .Pa /etc/rc.d/gptboot start-up script. This attribute is used to mark partitions that had the -.Ar bootonce +.Cm bootonce attribute set, but we failed to boot from them. Once we successfully boot, the .Pa /etc/rc.d/gptboot script will log all the partitions we failed to boot from and will remove the -.Ar bootfailed +.Cm bootfailed attributes. .El .Pp The scheme-specific attributes for MBR: -.Bl -tag -width ".Ar active" -.It Ar active +.Bl -tag -width ".Cm active" +.It Cm active .El .Pp The scheme-specific attributes for PC98: -.Bl -tag -width ".Ar bootable" -.It Ar active -.It Ar bootable +.Bl -tag -width ".Cm bootable" +.It Cm active +.It Cm bootable .El .Sh OPERATIONAL FLAGS Actions other than the @@ -747,7 +751,7 @@ reports about corruption. Any changes in corrupt table are prohibited except .Cm destroy and -.Cm recover . +.Cm recover . .Pp In case when only first sector is corrupt kernel can not detect GPT even if partition table is not corrupt. @@ -771,16 +775,15 @@ GEOM: provider: the secondary GPT table is corrupt or invalid. GEOM: provider: using the primary only -- recovery suggested. .Ed .Pp -Also -.Cm gpart -commands like -.Cm show , -.Cm status +Also +.Nm +commands like +.Cm show , status and .Cm list will report about corrupt table. .Pp -In case when the size of device has changed (e.g. volume expansion) the +In case when the size of device has changed (e.g.\& volume expansion) the secondary GPT header will become located not in the last sector. This is not a metadata corruption, but it is dangerous because any corruption of the primary GPT will lead to lost of partition table. @@ -789,19 +792,19 @@ Kernel reports about this problem with message: GEOM: provider: the secondary GPT header is not in the last LBA. .Ed .Pp -A corrupt table can be recovered with -.Cm gpart recover +A corrupt table can be recovered with +.Cm recover command. -This command does reconstruction of corrupt metadata using +This command does reconstruction of corrupt metadata using known valid metadata. Also it can relocate secondary GPT to the end of device. .Pp -.Pa NOTE : -The GEOM class PART can detect the same partition table on different GEOM +.Em NOTE : +The GEOM class PART can detect the same partition table on different GEOM providers and some of them will be marked as corrupt. Be careful when choosing a provider for recovering. If you choose incorrectly you can destroy the metadata of another GEOM class, -e.g. GEOM MIRROR or GEOM LABEL. +e.g.\& GEOM MIRROR or GEOM LABEL. .Sh SYSCTL VARIABLES The following .Xr sysctl 8 @@ -815,20 +818,21 @@ This variable controls the behaviour of metadata integrity checks. When integrity checks are enabled .Nm PART GEOM class verifies all generic partition parameters that it gets from the -disk metadata. If some inconsistency is detected, partition table will be +disk metadata. +If some inconsistency is detected, partition table will be rejected with a diagnostic message: -.Pa GEOM_PART: Integrity check failed (provider, scheme) . +.Sy "GEOM_PART: Integrity check failed (provider, scheme)" . .El .Sh EXIT STATUS Exit status is 0 on success, and 1 if the command fails. .Sh EXAMPLES Create GPT scheme on -.Pa ad0 . +.Pa ad0 : .Bd -literal -offset indent /sbin/gpart create -s GPT ad0 .Ed .Pp -Embed GPT bootstrap code into protective MBR. +Embed GPT bootstrap code into protective MBR: .Bd -literal -offset indent /sbin/gpart bootcode -b /boot/pmbr ad0 .Ed @@ -854,15 +858,19 @@ future need (e.g.\& from a ZFS partition). .Pp Create a 512MB-sized .Cm freebsd-ufs -partition that would contain UFS where the system boots from. +partition that would contain UFS where the system boots from: .Bd -literal -offset indent /sbin/gpart add -b 162 -s 1048576 -t freebsd-ufs ad0 .Ed .Pp Create MBR scheme on .Pa ada0 , -then create 30GB-sized FreeBSD slice, mark it active and -install boot0 boot manager: +then create 30GB-sized +.Fx +slice, mark it active and +install +.Nm boot0 +boot manager: .Bd -literal -offset indent /sbin/gpart create -s MBR ada0 /sbin/gpart add -t freebsd -s 30G ada0 @@ -870,7 +878,11 @@ install boot0 boot manager: /sbin/gpart bootcode -b /boot/boot0 ada0 .Ed .Pp -Now create BSD scheme (BSD label) with ability to have up to 20 partitions: +Now create +.Bx +scheme +.Pf ( Bx +label) with ability to have up to 20 partitions: .Bd -literal -offset indent /sbin/gpart create -s BSD -n 20 ada0s1 .Ed @@ -881,20 +893,22 @@ Create 1GB-sized UFS partition and 4GB-sized swap partition: /sbin/gpart add -t freebsd-swap -s 4G ada0s1 .Ed .Pp -Install bootstrap code for the BSD label: +Install bootstrap code for the +.Bx +label: .Bd -literal -offset indent /sbin/gpart bootcode -b /boot/boot ada0s1 .Ed .Pp Create VTOC8 scheme on -.Pa da0 . +.Pa da0 : .Bd -literal -offset indent /sbin/gpart create -s VTOC8 da0 .Ed .Pp Create a 512MB-sized .Cm freebsd-ufs -partition that would contain UFS where the system boots from. +partition that would contain UFS where the system boots from: .Bd -literal -offset indent /sbin/gpart add -s 512M -t freebsd-ufs da0 .Ed @@ -906,29 +920,29 @@ partition that would contain UFS and aligned on 4KB boundaries: /sbin/gpart add -s 15G -t freebsd-ufs -a 4k da0 .Ed .Pp -After having created all required partitions, embed bootstrap code into them. +After having created all required partitions, embed bootstrap code into them: .Bd -literal -offset indent /sbin/gpart bootcode -p /boot/boot1 da0 .Ed .Pp Create backup of partition table from -.Pa da0 +.Pa da0 : .Bd -literal -offset indent /sbin/gpart backup da0 > da0.backup .Ed .Pp Restore partition table from backup to -.Pa da0 +.Pa da0 : .Bd -literal -offset indent /sbin/gpart restore -l da0 < /mnt/da0.backup .Ed .Pp -Clone partition table from -.Pa ada0 -to -.Pa ada1 -and -.Pa ada2 +Clone partition table from +.Pa ada0 +to +.Pa ada1 +and +.Pa ada2 : .Bd -literal -offset indent /sbin/gpart backup ada0 | /sbin/gpart restore -F ada1 ada2 .Ed From f1a52c7ed64257aa9b67fc5fdfd55c17b5f7bd77 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 11:58:17 +0000 Subject: [PATCH 25/31] Don't pass -o1- to groff(1) by default. If ms(7) formatted document uses the .RP macro, a separate cover page is created as page 0 which is not otherwise output. The bug was hiding by a hack in troffrc that disables SGR support in grotty(1), which I'm going to remove now. For POLA reasons, still disable SGR support in grotty(1), by passing -P-c to groff(1). If we want SGR sequences in these documents, this can be removed. MFC after: 1 week --- share/mk/bsd.doc.mk | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/share/mk/bsd.doc.mk b/share/mk/bsd.doc.mk index 539d4c341dd..49b2d9b85fa 100644 --- a/share/mk/bsd.doc.mk +++ b/share/mk/bsd.doc.mk @@ -54,10 +54,10 @@ INDXBIB?= indxbib PIC?= pic REFER?= refer .for _dev in ${PRINTERDEVICE:Mascii} -ROFF.ascii?= groff -Tascii ${TRFLAGS} -mtty-char ${MACROS} -o${PAGES} +ROFF.ascii?= groff -Tascii -P-c ${TRFLAGS} -mtty-char ${MACROS} ${PAGES:C/^/-o/1} .endfor .for _dev in ${PRINTERDEVICE:Nascii} -ROFF.${_dev}?= groff -T${_dev} ${TRFLAGS} ${MACROS} -o${PAGES} +ROFF.${_dev}?= groff -T${_dev} ${TRFLAGS} ${MACROS} ${PAGES:C/^/-o/1} .endfor SOELIM?= soelim TBL?= tbl @@ -94,8 +94,6 @@ DFILE.${_dev}= ${DOC}.${_dev}${DCOMPRESS_EXT} .endif .endfor -PAGES?= 1- - UNROFF?= unroff HTML_SPLIT?= yes UNROFFFLAGS?= -fhtml From 0829f5978bcd8456082b6e4f521c86705cc4690b Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 12:02:53 +0000 Subject: [PATCH 26/31] Re-enable SGR support (ANSI color escapes) in grotty(1) by default. Our man(1) and bsd.doc.mk still disable it for POLA reasons via the -c option to grotty(1). PR: gnu/82353 --- contrib/groff/tmac/troffrc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/contrib/groff/tmac/troffrc b/contrib/groff/tmac/troffrc index 5defe8abc11..92b5fad85e7 100644 --- a/contrib/groff/tmac/troffrc +++ b/contrib/groff/tmac/troffrc @@ -50,12 +50,4 @@ troffrc!X100 troffrc!X100-12 troffrc!lj4 troff!lbp troffrc!html .\" Handle paper formats .do mso papersize.tmac . -.\" Disable SGR support in grotty(1). -.if n \{\ -. do nop \X'tty: sgr 0' -. sp -1 -. nr nl 0-1 -. nr % -1 -.\} -. .\" Don't let blank lines creep in here. From b70e20257c973d3a0df15d4198a60cc54b7a3af0 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 13:45:11 +0000 Subject: [PATCH 27/31] Don't use col(1) since grotty(1) never outputs reverse line feeds, and because col(1) mangles ANSI color escapes if enabled. Spaces to tabs compression is now done by passing -h to grotty(1). Discussed with: uqs --- usr.bin/man/man.conf.5 | 3 +-- usr.bin/man/man.sh | 18 +++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/usr.bin/man/man.conf.5 b/usr.bin/man/man.conf.5 index fdbd69e05b7..24f8226d51e 100644 --- a/usr.bin/man/man.conf.5 +++ b/usr.bin/man/man.conf.5 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 1, 2010 +.Dd June 3, 2011 .Os .Dt MAN.CONF 5 .Sh NAME @@ -72,7 +72,6 @@ For pages in a given language, overriding the default toolset for display is supported via the following definitions: .Bl -tag -offset indent -compact .It EQN Ns _ Ns Va LANG -.It COL Ns _ Ns Va LANG .It NROFF Ns _ Ns Va LANG .It PIC Ns _ Ns Va LANG .It TBL Ns _ Ns Va LANG diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh index 5905dc2abe0..11a920635dd 100755 --- a/usr.bin/man/man.sh +++ b/usr.bin/man/man.sh @@ -279,7 +279,7 @@ man_check_for_so() { # Usage: man_display_page # Display either the manpage or catpage depending on the use_cat variable man_display_page() { - local EQN COL NROFF PIC TBL TROFF REFER VGRIND + local EQN NROFF PIC TBL TROFF REFER VGRIND local IFS l nroff_dev pipeline preproc_arg tool # We are called with IFS set to colon. This causes really weird @@ -347,7 +347,7 @@ man_display_page() { # Allow language specific calls to override the default # set of utilities. l=$(echo $man_lang | tr [:lower:] [:upper:]) - for tool in EQN COL NROFF PIC TBL TROFF REFER VGRIND; do + for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do eval "$tool=\${${tool}_$l:-\$$tool}" done ;; @@ -368,7 +368,7 @@ man_display_page() { g) ;; # Ignore for compatability. p) pipeline="$pipeline | $PIC" ;; r) pipeline="$pipeline | $REFER" ;; - t) pipeline="$pipeline | $TBL"; use_col=yes ;; + t) pipeline="$pipeline | $TBL" ;; v) pipeline="$pipeline | $VGRIND" ;; *) usage ;; esac @@ -377,19 +377,12 @@ man_display_page() { pipeline="${pipeline#" | "}" else pipeline="$TBL" - use_col=yes fi if [ -n "$tflag" ]; then pipeline="$pipeline | $TROFF" else - pipeline="$pipeline | $NROFF" - - if [ -n "$use_col" ]; then - pipeline="$pipeline | $COL" - fi - - pipeline="$pipeline | $PAGER" + pipeline="$pipeline | $NROFF | $PAGER" fi if [ $debug -gt 0 ]; then @@ -928,14 +921,13 @@ do_whatis() { # User's PATH setting decides on the groff-suite to pick up. EQN=eqn -NROFF='groff -S -P-c -Wall -mtty-char -man' +NROFF='groff -S -P-ch -Wall -mtty-char -man' PIC=pic REFER=refer TBL=tbl TROFF='groff -S -man' VGRIND=vgrind -COL=/usr/bin/col LOCALE=/usr/bin/locale STTY=/bin/stty SYSCTL=/sbin/sysctl From 190367ef1cd962463f51036d6069457db85eb272 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 3 Jun 2011 13:47:05 +0000 Subject: [PATCH 28/31] Properly return an ENOBUFS error if a write to a tun(4) device fails due to m_uiotombuf() failing. While here, trim unneeded error handling related to tuninit() since it can never fail. Submitted by: Martin Birgmeier la5lbtyi aon at Reviewed by: glebius MFC after: 1 week --- sys/net/if_tun.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 4e727d9df3f..49a524936f2 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -126,7 +126,7 @@ static void tunclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev); static void tuncreate(const char *name, struct cdev *dev); static int tunifioctl(struct ifnet *, u_long, caddr_t); -static int tuninit(struct ifnet *); +static void tuninit(struct ifnet *); static int tunmodevent(module_t, int, void *); static int tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct route *ro); @@ -494,14 +494,13 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) return (0); } -static int +static void tuninit(struct ifnet *ifp) { struct tun_softc *tp = ifp->if_softc; #ifdef INET struct ifaddr *ifa; #endif - int error = 0; TUNDEBUG(ifp, "tuninit\n"); @@ -528,7 +527,6 @@ tuninit(struct ifnet *ifp) if_addr_runlock(ifp); #endif mtx_unlock(&tp->tun_mtx); - return (error); } /* @@ -552,12 +550,12 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) mtx_unlock(&tp->tun_mtx); break; case SIOCSIFADDR: - error = tuninit(ifp); - TUNDEBUG(ifp, "address set, error=%d\n", error); + tuninit(ifp); + TUNDEBUG(ifp, "address set\n"); break; case SIOCSIFDSTADDR: - error = tuninit(ifp); - TUNDEBUG(ifp, "destination address set, error=%d\n", error); + tuninit(ifp); + TUNDEBUG(ifp, "destination address set\n"); break; case SIOCSIFMTU: ifp->if_mtu = ifr->ifr_mtu; @@ -857,7 +855,6 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag) struct tun_softc *tp = dev->si_drv1; struct ifnet *ifp = TUN2IFP(tp); struct mbuf *m; - int error = 0; uint32_t family; int isr; @@ -877,7 +874,7 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag) if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, 0, M_PKTHDR)) == NULL) { ifp->if_ierrors++; - return (error); + return (ENOBUFS); } m->m_pkthdr.rcvif = ifp; From 0330cb3bf7b1f5c58872cdf0516b2add071e79ef Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 3 Jun 2011 13:49:18 +0000 Subject: [PATCH 29/31] Update disk's stripesize and stripeoffset parameters on provider open. They are media-dependent and may change in run-time, same as sectorsize and/or mediasize. SCSI devices return physical sector size and offset via READ CAPACITY(16) command and so can not report it until media inserted or at least until probe sequence completed. UNMAP support is also reported there. --- sys/geom/geom_disk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index a051772463d..e663e3dd29e 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -154,6 +154,12 @@ g_disk_access(struct g_provider *pp, int r, int w, int e) } pp->mediasize = dp->d_mediasize; pp->sectorsize = dp->d_sectorsize; + if (dp->d_flags & DISKFLAG_CANDELETE) + pp->flags |= G_PF_CANDELETE; + else + pp->flags &= ~G_PF_CANDELETE; + pp->stripeoffset = dp->d_stripeoffset; + pp->stripesize = dp->d_stripesize; dp->d_flags |= DISKFLAG_OPEN; if (dp->d_maxsize == 0) { printf("WARNING: Disk drive %s%d has no d_maxsize\n", From a6a3e8561d046a7e9cabc322c055903f47e5d880 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Fri, 3 Jun 2011 14:34:38 +0000 Subject: [PATCH 30/31] When MANCOLOR environment variable is set, enable ANSI color escapes in grotty(1). This makes it possible to view colorized manpages in color. When MANPAGER environment variable is set, use it instead of PAGER. Why another environment variable, one might ask? With color output enabled, both a terminal and a pager should support the ANSI color escapes. On a supporting terminal, less(1) with option -R would be such a pager, while "more -s" (the current default pager for man(1)) will show garbage. It means a different default pager is needed when color output is enabled, but many people have PAGER set customary, and it's unlikely to support ANSI color escapes, so introducing yet another variable (MANPAGER) seemed like a good option to me: - if MANPAGER is set, use that unconditionally; - if you disable color support (it is by default), and don't set MANPAGER, you get an old behavior: -P pager, $PAGER, "more -s", in that order; - if you enable color support (by setting MANCOLOR), and don't set MANPAGER, we ignore PAGER which is unlikely to support ANSI color escapes, and you get: -P pager, "less -Rs", in that order; - you might have good reasons for different man(1) and general purpose pagers; - later versions of GNU man(1) support MANPAGER. --- usr.bin/man/man.1 | 20 +++++++++++++++++--- usr.bin/man/man.sh | 32 ++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 index 133d5369908..a9002ece8ad 100644 --- a/usr.bin/man/man.1 +++ b/usr.bin/man/man.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 2, 2011 +.Dd June 3, 2011 .Dt MAN 1 .Os .Sh NAME @@ -73,8 +73,12 @@ environment variable. .It Fl P Ar pager Use specified pager. Defaults to +.Ic "less -sR" +if color support is enabled, or .Ic "more -s" . Overrides the +.Ev MANPAGER +environment variable, which in turn overrides the .Ev PAGER environment variable. .It Fl S Ar mansect @@ -289,9 +293,19 @@ Otherwise, if set to a special value .Dq Li tty , and output is to a terminal, the pages may be displayed over the whole width of the screen. -.It Ev PAGER +.It Ev MANCOLOR +If set, enables color support. +.It Ev MANPAGER Program used to display files. -If unset, +.Pp +If unset, and color support is enabled, +.Ic "less -sR" +is used. +.Pp +If unset, and color support is disabled, then +.Ev PAGER +is used. +If that has no value either, .Ic "more -s" is used. .El diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh index 11a920635dd..98749a60a19 100755 --- a/usr.bin/man/man.sh +++ b/usr.bin/man/man.sh @@ -294,10 +294,10 @@ man_display_page() { ret=0 else if [ $debug -gt 0 ]; then - decho "Command: $cattool $catpage | $PAGER" + decho "Command: $cattool $catpage | $MANPAGER" ret=0 else - eval "$cattool $catpage | $PAGER" + eval "$cattool $catpage | $MANPAGER" ret=$? fi fi @@ -356,6 +356,10 @@ man_display_page() { ;; esac + if [ -z "$MANCOLOR" ]; then + NROFF="$NROFF -P-c" + fi + if [ -n "${use_width}" ]; then NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" fi @@ -382,7 +386,7 @@ man_display_page() { if [ -n "$tflag" ]; then pipeline="$pipeline | $TROFF" else - pipeline="$pipeline | $NROFF | $PAGER" + pipeline="$pipeline | $NROFF | $MANPAGER" fi if [ $debug -gt 0 ]; then @@ -484,7 +488,7 @@ man_parse_args() { while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do case "${cmd_arg}" in M) MANPATH=$OPTARG ;; - P) PAGER=$OPTARG ;; + P) MANPAGER=$OPTARG ;; S) MANSECT=$OPTARG ;; a) aflag=aflag ;; d) debug=$(( $debug + 1 )) ;; @@ -808,7 +812,7 @@ search_whatis() { bad=${bad#\\n} if [ -n "$good" ]; then - echo -e "$good" | $PAGER + echo -e "$good" | $MANPAGER fi if [ -n "$bad" ]; then @@ -832,13 +836,21 @@ setup_cattool() { } # Usage: setup_pager -# Correctly sets $PAGER +# Correctly sets $MANPAGER setup_pager() { # Setup pager. - if [ -z "$PAGER" ]; then - PAGER="more -s" + if [ -z "$MANPAGER" ]; then + if [ -n "$MANCOLOR" ]; then + MANPAGER="less -sR" + else + if [ -n "$PAGER" ]; then + MANPAGER="$PAGER" + else + MANPAGER="more -s" + fi + fi fi - decho "Using pager: $PAGER" + decho "Using pager: $MANPAGER" } # Usage: trim string @@ -921,7 +933,7 @@ do_whatis() { # User's PATH setting decides on the groff-suite to pick up. EQN=eqn -NROFF='groff -S -P-ch -Wall -mtty-char -man' +NROFF='groff -S -P-h -Wall -mtty-char -man' PIC=pic REFER=refer TBL=tbl From e375b204002014a4f81f15d734947277ee3e9049 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Fri, 3 Jun 2011 14:57:38 +0000 Subject: [PATCH 31/31] Explicitly initialize the packet buffer to NULL after we unmap the zero copy buffers. This fixes a segfault on exit due to calling free on a bogus pointer. This should be considered a temporary stop gap fix to avoid the crash. The complete fix re-shuffles the initializations of some of the clean-up pointers. The details of the fix can be found in the libpcap git repository: commit bc8209b71e928870b0f172d43b174ab27ba24394 Proded by: kevlo, rpaulo MFC after: 2 weeks Submitted by: Anton Yuzhaninov --- contrib/libpcap/pcap-bpf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/libpcap/pcap-bpf.c b/contrib/libpcap/pcap-bpf.c index 10dcfd14f58..5e3d3eaca2d 100644 --- a/contrib/libpcap/pcap-bpf.c +++ b/contrib/libpcap/pcap-bpf.c @@ -1281,6 +1281,7 @@ pcap_cleanup_bpf(pcap_t *p) munmap(p->md.zbuf1, p->md.zbufsize); if (p->md.zbuf2 != MAP_FAILED && p->md.zbuf2 != NULL) munmap(p->md.zbuf2, p->md.zbufsize); + p->buffer = NULL; } #endif if (p->md.device != NULL) {