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. 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) { diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index 93b28ac8c9c..ae9f4b7b451 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 > 0) + 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 > 0 ) + 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); 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 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 diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index 7418e1e9a22..8e933022390 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -114,11 +114,12 @@ struct disk_params { u_int64_t sectors; /* Total number sectors */ }; -#define TRIM_MAX_BLOCKS 4 -#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64 +#define TRIM_MAX_BLOCKS 8 +#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) +#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 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; 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 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) 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", 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); 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; 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/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..c200b4c2a15 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -75,8 +75,7 @@ .globl kernbase .set kernbase, KERNBASE -#define TMPSTKSZ 8192 /* 8K temporary stack */ -#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ +#define TMPSTKSZ 16384 /* 16K temporary 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/aim/machdep.c b/sys/powerpc/aim/machdep.c index 65c9db1dae3..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; @@ -251,7 +252,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 +263,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 +278,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); @@ -338,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: @@ -353,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 } /* @@ -368,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 @@ -503,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,8 +531,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); - isync(); + mtmsr(PSL_KERNSET & ~PSL_EE); /* * Initialize params/tunables that are derived from memsize diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 44101410652..be80455dab6 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -587,25 +587,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) { @@ -723,7 +706,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; @@ -752,7 +734,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 b2e104a2fd6..84e8ecd3919 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -165,8 +165,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) @@ -476,25 +476,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) { @@ -710,10 +693,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; @@ -898,7 +880,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 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; 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/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/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) diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index 9af4051999a..2f1e770941d 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -66,7 +66,8 @@ static struct mem_region OFfree[OFMEM_REGIONS + 3]; static int nOFmem; extern register_t ofmsr[5]; -static int (*ofwcall)(void *); +int ofwcall(void *); +extern void *openfirmware_entry; static void *fdt; int ofw_real_mode; @@ -318,19 +319,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 +333,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 { 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); +} + + diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 index 58f43e5864e..a9002ece8ad 100644 --- a/usr.bin/man/man.1 +++ b/usr.bin/man/man.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 1, 2010 +.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 @@ -283,9 +287,25 @@ Restricts manual sections searched to the specified colon delimited list. Corresponds to the .Fl S option. -.It Ev PAGER +.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 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.conf.5 b/usr.bin/man/man.conf.5 index 6326bc1ebf1..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 @@ -112,7 +111,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 diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh index 762970d076b..98749a60a19 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 @@ -275,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 @@ -290,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 @@ -343,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 ;; @@ -352,6 +356,14 @@ 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 + if [ -n "$MANROFFSEQ" ]; then set -- -$MANROFFSEQ while getopts 'egprtv' preproc_arg; do @@ -360,7 +372,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 @@ -369,19 +381,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 | $MANPAGER" fi if [ $debug -gt 0 ]; then @@ -483,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 )) ;; @@ -562,6 +567,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 @@ -667,7 +701,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 @@ -778,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 @@ -802,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 @@ -891,15 +933,15 @@ 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-h -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 debug=0 diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig index bef57598bb2..37fe8c65dbe 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,12 +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 + # 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} 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) { 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. */ 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() {