summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2011-06-03 17:09:15 +0000
committerattilio <attilio@FreeBSD.org>2011-06-03 17:09:15 +0000
commit91525e4ff96713dd3149a3477069cc7213d0abae (patch)
treee57c9894493b064186bad81144f2f35caf5f8b21
parent3c36d056695bef4a3aa0002c977fc1999621600e (diff)
parent9c392f3f9121f469140929d45260ed31420f7126 (diff)
downloadFreeBSD-src-91525e4ff96713dd3149a3477069cc7213d0abae.zip
FreeBSD-src-91525e4ff96713dd3149a3477069cc7213d0abae.tar.gz
MFC
-rw-r--r--contrib/groff/tmac/troffrc8
-rw-r--r--contrib/libpcap/pcap-bpf.c1
-rw-r--r--sbin/geom/class/part/geom_part.c51
-rw-r--r--sbin/geom/class/part/gpart.8156
-rw-r--r--share/mk/bsd.doc.mk6
-rw-r--r--sys/cam/ata/ata_da.c36
-rw-r--r--sys/conf/files.powerpc5
-rw-r--r--sys/dev/ath/ath_hal/ah.h13
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212.h2
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_misc.c14
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212reg.h1
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416.h2
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_misc.c29
-rw-r--r--sys/geom/geom_disk.c6
-rw-r--r--sys/geom/part/g_part.c17
-rw-r--r--sys/net/if_tun.c17
-rw-r--r--sys/powerpc/aim/interrupt.c4
-rw-r--r--sys/powerpc/aim/locore32.S13
-rw-r--r--sys/powerpc/aim/locore64.S134
-rw-r--r--sys/powerpc/aim/machdep.c29
-rw-r--r--sys/powerpc/aim/mmu_oea.c20
-rw-r--r--sys/powerpc/aim/mmu_oea64.c26
-rw-r--r--sys/powerpc/aim/moea64_native.c6
-rw-r--r--sys/powerpc/aim/mp_cpudep.c5
-rw-r--r--sys/powerpc/aim/slb.c26
-rw-r--r--sys/powerpc/aim/trap_subr64.S46
-rw-r--r--sys/powerpc/include/rtas.h61
-rw-r--r--sys/powerpc/include/slb.h2
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c18
-rw-r--r--sys/powerpc/ofw/ofw_real.c7
-rw-r--r--sys/powerpc/ofw/ofwcall32.S154
-rw-r--r--sys/powerpc/ofw/ofwcall64.S290
-rw-r--r--sys/powerpc/ofw/ofwmagic.S (renamed from sys/powerpc/aim/ofwmagic.S)0
-rw-r--r--sys/powerpc/ofw/rtas.c243
-rw-r--r--usr.bin/man/man.126
-rw-r--r--usr.bin/man/man.conf.55
-rwxr-xr-xusr.bin/man/man.sh88
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig9
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv46
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv66
-rw-r--r--usr.sbin/mountd/mountd.c243
-rw-r--r--usr.sbin/rpc.lockd/lockd.c249
-rw-r--r--usr.sbin/rpc.statd/statd.c240
45 files changed, 1814 insertions, 508 deletions
diff --git a/contrib/groff/tmac/troffrc b/contrib/groff/tmac/troffrc
index 5defe8a..92b5fad 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 10dcfd1..5e3d3ea 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 93b28ac..ae9f4b7 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 e4f6cc6..940620c 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 539d4c3..49b2d9b 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 7418e1e..8e93302 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 7d4e2a2..9dcc867 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 bbea10a..165d919 100644
--- a/sys/dev/ath/ath_hal/ah.h
+++ b/sys/dev/ath/ath_hal/ah.h
@@ -736,6 +736,16 @@ typedef struct {
/*
+ * 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.
*
* Clients of the HAL call ath_hal_attach to obtain a reference to an
@@ -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 a9ea4ef..16394a3 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 90605cf..5999a60 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 ad1b7eb..276671d 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 f99b203..15c1a58 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 984b5e8..510afe0 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 aa9d97b..22d05ff 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 4b1ba22..2c08730 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 a051772..e663e3d 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 a3f8575..f24e7b5 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 4e727d9..49a5249 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 b06fb92..d1e3655 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 64bf81e..35ea99b 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 acdc8a1..c200b4c 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:
@@ -208,122 +192,6 @@ 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()
*
* Similar to setjmp to setup for handling faults on accesses to user memory.
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index 65c9db1..3ccae91 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 4410141..be80455 100644
--- a/sys/powerpc/aim/mmu_oea.c
+++ b/sys/powerpc/aim/mmu_oea.c
@@ -587,26 +587,9 @@ 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)
{
const struct ofw_map *mapa;
@@ -723,7 +706,6 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
mem_regions(&pregions, &pregions_sz, &regions, &regions_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 b2e104a..84e8ecd 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,26 +476,9 @@ 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)
{
const struct ofw_map *mapa;
@@ -710,10 +693,9 @@ moea64_early_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelen
mem_regions(&pregions, &pregions_sz, &regions, &regions_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 bca51ab..9e5174f 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 3ee22f3..d617fde 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 1fafbb4..df493b4 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 7156edb..5d4148a 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 0000000..5b18632
--- /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 <sys/cdefs.h>
+#include <sys/types.h>
+#include <dev/ofw/openfirm.h>
+
+/*
+ * 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 f675e15..637110c 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 9af4051..2f1e770 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 617f9be..1fc2ed1 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 0000000..06cc105
--- /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 <sys/syscall.h>
+
+#include <machine/trap.h>
+#include <machine/param.h>
+#include <machine/spr.h>
+#include <machine/asm.h>
+
+#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 0000000..1fb78e8
--- /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 <sys/syscall.h>
+
+#include <machine/trap.h>
+#include <machine/param.h>
+#include <machine/spr.h>
+#include <machine/asm.h>
+
+#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
index f44f1e5..f44f1e5 100644
--- a/sys/powerpc/aim/ofwmagic.S
+++ b/sys/powerpc/ofw/ofwmagic.S
diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c
new file mode 100644
index 0000000..59692c9
--- /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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/pmap.h>
+#include <machine/rtas.h>
+#include <machine/stdarg.h>
+
+#include <dev/ofw/openfirm.h>
+
+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 58f43e5..a9002ec 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 6326bc1..24f8226 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 762970d..98749a6 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 bef5759..37fe8c6 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 dc6da7e..72dc0ee 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 c9fad54..70bd203 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 65bf44f..01a27eb 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 fb9e536..b3402ff 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 <rpcsvc/nlm_prot.h>
+#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));
@@ -617,6 +793,23 @@ create_service(struct netconfig *nconf)
}
/*
+ * 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.
*/
void
diff --git a/usr.sbin/rpc.statd/statd.c b/usr.sbin/rpc.statd/statd.c
index b8b4311..ff537f8 100644
--- a/usr.sbin/rpc.statd/statd.c
+++ b/usr.sbin/rpc.statd/statd.c
@@ -39,6 +39,7 @@
__FBSDID("$FreeBSD$");
#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
@@ -55,13 +56,21 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#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;
-
-void create_service(struct netconfig *nconf);
+static int mallocd_svcport = 0;
+static int *sock_fd;
+static int sock_fdcnt;
+static int sock_fdpos;
+
+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()
{
OpenPOWER on IntegriCloud